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

moosetechnology / VerveineJ / 23642838101

27 Mar 2026 10:52AM UTC coverage: 51.994% (-0.05%) from 52.039%
23642838101

Pull #205

github

web-flow
Merge 4adac8808 into d564a6404
Pull Request #205: Add support for primitive types in generics

1973 of 3970 branches covered (49.7%)

Branch coverage included in aggregate %.

12 of 35 new or added lines in 4 files covered. (34.29%)

234 existing lines in 2 files now uncovered.

4362 of 8214 relevant lines covered (53.1%)

2.15 hits per line

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

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

49
import ch.akuhn.fame.Repository;
50
import fr.inria.verveine.extractor.java.utils.ImplicitVarBinding;
51
import fr.inria.verveine.extractor.java.utils.Util;
52

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

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

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

79
        public static final int UNKNOWN_MODIFIERS = 0;
80
        public static final String MODIFIER_PUBLIC   = "public";
81
        public static final String MODIFIER_PRIVATE  = "private";
82
        public static final String MODIFIER_PROTECTED= "protected";
83
        public static final String MODIFIER_PACKAGE = "package";
84

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

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

95
        /**
96
         * The FAMIX repository where all FAMIX entities are created and stored
97
         */
98
        protected Repository famixRepo;
99

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

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

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

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

139

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

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

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

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

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

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

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

236
                return ret;
2✔
237
        }
238

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

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

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

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

292
                        mapEntityToName(name, fmx);
4✔
293
                        
294
                        // put new entity in Famix repository
295
                        famixRepoAdd((Entity) fmx);
4✔
296
                }
297

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

319
                if (bnd != null) {
2✔
320
                        fmx = (T) getEntityByKey(bnd);
4✔
321
                        if (fmx != null) {
2✔
322
                                return fmx;
2✔
323
                        }
324
                }
325

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

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

345

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

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

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

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

414
        ///// ensure Famix Relationships /////
415

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

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

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

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

463
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6!
464
                        
465
                        TTypeArgument typeArgument;
466
                        try {
467
                                typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7✔
NEW
UNCOV
468
                        } catch(ClassCastException e) {
×
469
                                
NEW
UNCOV
470
                                throw e;
×
471
                        }
1✔
472
                        
473
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7✔
474

475
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5✔
476
                        association.addConcretization(concretization);
3✔
477
                }
1✔
478

479
                return association;
2✔
480
        }
481

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

493
                Concretization concretization = new Concretization();
4✔
494
                concretization.setTypeArgument(typeArgument);
3✔
495
                concretization.setTypeParameter(typeParameter);
3✔
496

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

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

526
                implementation.setImplementingClass(implementingClass);
3✔
527
                implementation.setMyInterface(myInterface);
3✔
528
                chainPrevNext(prev, implementation);
4✔
529
                famixRepoAdd(implementation);
3✔
530
                return implementation;
2✔
531
        }
532

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

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

567
                if (prev == null) {
2✔
568
                        for (TReference existingRef : src.getOutgoingReferences()) {
7!
UNCOV
569
                                if (existingRef.getReferredEntity() == tgt) {
×
UNCOV
570
                                        return (Reference) existingRef;
×
571
                                }
UNCOV
572
                        }
×
573
                }
574

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

584
                ref.setReferredEntity(tgt);
3✔
585
                ref.setReferencer(src);
3✔
586
                chainPrevNext(prev,ref);
4✔
587
                famixRepoAdd(ref);
3✔
588

589
                return ref;
2✔
590
        }
591

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

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

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

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

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

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

696

697
        /**
698
         * Returns a Famix EntityTyping between a typed entity and a type.
699
         * @param typedEntity -- the typed entity
700
         * @param declaredType -- the declared type
701
         * @return the FamixEntityTyping
702
         */
703
        public EntityTyping ensureFamixEntityTyping(ITypeBinding declaredTypeBnd, TTypedEntity typedEntity, TType declaredType) {
704
                if ( (typedEntity == null) || (declaredType == null) ) {
4!
705
                        return null;
2✔
706
                }
707
                EntityTyping typing;
708
                if (declaredTypeBnd != null && declaredTypeBnd.isParameterizedType()) {
5✔
709
                        typing = (ParametricEntityTyping)buildFamixParametricAssociation(new ParametricEntityTyping(), declaredTypeBnd.getErasure().getTypeParameters(), declaredTypeBnd.getTypeArguments());
13✔
710
                } else {
711
                        typing = new EntityTyping();
4✔
712
                }
713
                typing.setTypedEntity(typedEntity);
3✔
714
                typing.setDeclaredType(declaredType);
3✔
715
                famixRepoAdd(typing);
3✔
716
                
717
                return typing;
2✔
718
        }
719

720

721
        ///// Special Case: ImplicitVariables /////
722

723
        /**
724
         * Returns the Famix ImplicitVariable associated to the given binding and name (self or super).
725
         * See also {@link #getEntityByKey(IBinding)}
726
         * @param bnd -- the binding
727
         * @return the Famix Entity associated to the binding or null if not found
728
         */
729
        @Deprecated
730
        public ImplicitVariable getImplicitVariableByBinding(IBinding bnd, String iv_name) {
UNCOV
731
                return getImplicitVariableByType((Class)getEntityByKey(bnd), iv_name);
×
732
        }
733
        
734
        /**
735
         * Returns the Famix ImplicitVariable associated to the given FamixType.
736
         * @param type -- the FamixType
737
         * @param name -- name of the ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
738
         * @return the Famix ImplicitVariable associated to the Type or null if not found
739
         */
740
        @Deprecated
741
        public ImplicitVariable getImplicitVariableByType(Type type, String name) {
742
                ImplicitVars iv = typeToImpVar.get(type);
×
743
                ImplicitVariable ret = null;
×
744
                
745
                if (iv == null) {
×
746
                        iv = new ImplicitVars();
×
747
                }
748
                
749
                if (name.equals(THIS_NAME)) {
×
UNCOV
750
                        ret = iv.self_iv;
×
751
                }
UNCOV
752
                else if (name.equals(SUPER_NAME)) {
×
UNCOV
753
                        ret = iv.super_iv;
×
754
                }
755

UNCOV
756
                return ret;
×
757
        }
758

759
        ///// Special Case: "Uniq" Entities /////
760

761
        /**
762
         * Creates or recovers a Famix Named Entity uniq for the given name.
763
         * For some specific entities we don't allow two of them with the same name.
764
         * This is the case e.g. for the default package, or the Java class "Object" and its package "java.lang".
765
         * @param fmxClass -- the Famix class of the instance to create
766
         * @param key -- a potential binding for the entity
767
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
768
         * @return the uniq Famix Entity for this binding and/or name
769
         */
770
        @SuppressWarnings("unchecked")
771
        public <T extends NamedEntity> T ensureFamixUniqEntity(java.lang.Class<T> fmxClass, IBinding key, String name) {
772
                T fmx = null;
2✔
773
                
774
                if (name == null) {
2!
UNCOV
775
                        return null;
×
776
                }
777
                
778
                if (key != null) {
2✔
779
                        fmx = (T) getEntityByKey(key);
5✔
780
                }
781
                
782
                if (fmx == null) {
2✔
783
                        Collection<T> l = getEntityByName( fmxClass, name);
5✔
784
                        if (l.size() > 0) {
3✔
785
                                fmx = l.iterator().next();
6✔
786
                        }
787
                        else {
788
                                fmx = createFamixEntity(fmxClass, name);
6✔
789
                        }
790
                        
791
                        if (key != null) {
2✔
792
                                // may happen for example if the entity was first created without binding
793
                                // and we find a binding for it later
794
                                keyToEntity.put(key, fmx);
6✔
795
                        }
796
                }
797

798
                return fmx;
2✔
799
        }
800

801
        /**
802
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
803
         *
804
         * @return a Famix class
805
         */
806
        public Class ensureFamixClassStubOwner() {
807
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7✔
808
                if (fmx != null) {
2!
809
                        fmx.setTypeContainer( ensureFamixPackageDefault());
4✔
810
                }
811
                ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
8✔
812

813
                return fmx;
2✔
814
        }
815

816
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
UNCOV
817
                if (ctxt == null) {
×
818
                        return null;
×
819
                }
820
                
UNCOV
821
                for (TType candidate : ctxt.getTypes()) {
×
UNCOV
822
                        if (candidate.getName().equals(name) ) {
×
UNCOV
823
                                return (Type) candidate;
×
824
                        }
UNCOV
825
                }
×
826
                
UNCOV
827
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
828
        }
829

830
        /**
831
         * Returns a Famix Package associated with its IPackageBinding and/or fully qualified name.
832
         * The Entity is created if it does not exist.
833
         * We assume that Namespaces must be uniq for a given name
834
         * Also creates or recovers recusively it's parent namespaces.<br>
835
         * At least one of <b>bnd</b> and <b>name</b> must be non null.
836
         *
837
         * @param bnd  -- the JDT Binding that may be used as a uniq key to recover this namespace
838
         * @param name -- fully qualified name of the namespace (e.g. 'java.lang')
839
         * @return the Famix Namespace found or created. May return null in case of a Famix error
840
         */
841
        public Package ensureFamixPackage(IPackageBinding bnd, String name) {
842
                Package fmx;
843
                Package parent;
844

845
                if ((name == null) && (bnd != null)) {
4!
846
                        name = bnd.getName();
3✔
847
                }
848

849
                if ((name == null) || name.equals("")) {
6!
850
                        return ensureFamixPackageDefault();
3✔
851
                } else {
852
                        /* Note: Packages are created with their fully-qualified name to simplify recovering when we don't have a binding
853
                         * (for example when creating parent packages of a package we have a binding for).
854
                         * Because the preferred solution in Moose is to give their simple names to packages, they must be post-processed when
855
                         * all is said and done. */
856
                        fmx = ensureFamixUniqEntity(Package.class, bnd, name);
7✔
857
                        String parentName = removeLastPartOfPackageName(name);
4✔
858
                        if (parentName.length() > 0) {
3✔
859
                                parent = ensureFamixPackage(null, parentName);
5✔
860
                                // set the parentscope relationship
861
                                if ((parent != null) && (fmx != null) && (fmx.getParentPackage() == null)) {
7!
862
                                        parent.addChildEntities(fmx);
3✔
863
                                }
864
                        }
865
                }
866

867
                return fmx;
2✔
868
        }
869

870
        /**
871
         * Creates or recovers a default Famix Package.
872
         * Because this package does not really exist, it has no binding.
873
         *
874
         * @return a Famix Namespace
875
         */
876
        public Package ensureFamixPackageDefault() {
877
        return ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7✔
878
        }
879

880
        /**
881
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
882
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
883
         *
884
         * @param bnd -- a potential binding for the "java.lang" package
885
         * @return a Famix Namespace for "java.lang"
886
         */
887
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
888

889
        return this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5✔
890
        }
891

892
        /**
893
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
894
         */
895
        public Package getFamixPackageDefault() {
896
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5✔
897
                if (l.size() > 0) {
3!
898
                        return l.iterator().next();
5✔
899
                } else {
UNCOV
900
                        return null;
×
901
                }
902
        }
903

904
        /**
905
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
906
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
907
         * @param bnd -- binding for the type to create
908
         * @param name of the type
909
         * @param owner of the type
910
         * @param ctxt -- context of use of the type
911
         */
912
        public Type ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
913
                
914
                Type fmx;
915

916
                if (bnd == null) {
2✔
917
                        if (name == null) {
2!
918
                                return null;
2✔
919
                        }
UNCOV
920
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
UNCOV
921
                        if (fmx != null) {
×
922
                                return fmx;
×
923
                        }
924

UNCOV
925
                        if ((owner instanceof TParametricEntity)) {
×
UNCOV
926
                                return this.ensureFamixTypeParameter(null, name, owner);
×
927
                        }
928
                        else {
UNCOV
929
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
UNCOV
930
                                fmx.setTypeContainer(owner);
×
UNCOV
931
                                return fmx;
×
932
                        }
933
                }
934

935
                // bnd != null
936

937
                fmx = (Type) getEntityByKey(bnd);
5✔
938
                if (fmx != null) {
2✔
939
                        return fmx;
2✔
940
                }
941

942
                if (bnd.isArray()) {
3✔
943
                        bnd = bnd.getElementType();
3✔
944
                }
945

946
                if (bnd.isPrimitive()) {
3✔
947
                        return this.ensureFamixPrimitiveType(bnd, name);
5✔
948
                }
949

950
                if (bnd.isEnum()) {
3!
UNCOV
951
                        return this.ensureFamixEnum(bnd, name, owner);
×
952
                }
953
 
954
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
955
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
956
                }
957

958
                if (bnd.isCapture()) {
3✔
959
                        if (bnd.getErasure().isInterface()) {
4!
960
                                return this.ensureFamixInterface(bnd.getErasure(), name, owner, /*isGeneric*/true, modifiers);
9✔
961
                        }
962
                        else {
UNCOV
963
                                return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
×
964
                        }
965
                }
966

967
                if (bnd.isAnnotation()) {
3✔
968
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
7✔
969
                }
970

971
                if (bnd.isInterface()) {
3✔
972
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19✔
973
                }
974

975
                if (isThrowable(bnd)) {
4✔
976
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8✔
977
                }
978
                if (bnd.isClass()) {
3✔
979
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20!
980
                }
981
                if(bnd.isWildcardType()) {
3✔
982
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8✔
983
                }
984

985
                //otherwise (none of the above)
986

987
                if (name == null) {
2✔
988
                        name = bnd.getName();
3✔
989
                }
990

991
                if (owner == null) {
2!
992
                        owner = (TWithTypes) this.ensureOwner(bnd);
5✔
993
                }
994

995
                if (bnd.isTypeVariable() ) {
3!
996
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6✔
997
                        return fmx;
2✔
998
                }
999

UNCOV
1000
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
UNCOV
1001
                fmx.setTypeContainer(owner);
×
UNCOV
1002
                return fmx;
×
1003
        }
1004

1005
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1006
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
1007
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1008
        }
1009
        
1010
        public Type ensureFamixType(ITypeBinding bnd) {
1011
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1012
        }
1013

1014
        public boolean isThrowable(ITypeBinding bnd) {
1015
                if (bnd == null) {
2!
UNCOV
1016
                        return false;
×
1017
                }
1018
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5✔
1019
                        return true;
2✔
1020
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5✔
1021
                        return false;
2✔
1022
                }
1023
                else {
1024
                        return isThrowable(bnd.getSuperclass());
5✔
1025
                }
1026
        }
1027

1028
        /**
1029
         * Returns a Famix Class associated with the ITypeBinding.
1030
         * The Entity is created if it does not exist.
1031
         * @param name -- the name of the Famix Class (MUST NOT be null, but this is not checked)
1032
         * @param owner -- package defining the class (should not be null, but it will work if it is)
1033
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1034
         */
1035
        @SuppressWarnings("deprecation")
1036
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1037
                Class fmx;
1038

1039
                // --------------- some special cases
1040
                if (bnd != null) {
2✔
1041
                        if (bnd.isArray()) {
3!
1042
                                bnd = bnd.getElementType();
×
1043
                        }
1044

1045
                        // for inner classes defined in generics !!! For others should not change anything
1046
                        bnd = bnd.getErasure();
3✔
1047
                }
1048

1049
                // ---------------- to avoid useless computations if we can
1050
                fmx = (Class) getEntityByKey(bnd);
5✔
1051
                if (fmx != null) {
2✔
1052
                        return fmx;
2✔
1053
                }
1054

1055
                // --------------- name
1056
                if (name == null) {
2✔
1057
                        if (bnd == null) {
2!
UNCOV
1058
                                return null;  // not much we can do
×
1059
                        } else if (!bnd.isAnonymous()) {
3!
1060
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1061
                        } else { // anonymous class
UNCOV
1062
                                if (bnd.getSuperclass() != null) {
×
UNCOV
1063
                                        name = bnd.getSuperclass().getName();
×
1064
                                }
UNCOV
1065
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
UNCOV
1066
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
UNCOV
1067
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
UNCOV
1068
                                                name = bnd.getInterfaces()[0].getName();
×
1069
                                        }
1070
                                        else {
UNCOV
1071
                                                name = "???";
×
1072
                                        }
1073
                                }
UNCOV
1074
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1075
                        }
1076
                }
1077

1078
        // If we have java.lang.Object we should ensure we create this class
1079
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7✔
1080
                        return ensureFamixClassObject();
3✔
1081
                }
1082

1083
                // --------------- owner
1084
                if (owner == null) {
2✔
1085
                        if (bnd != null) {
2✔
1086
                                owner = ensureOwner(bnd);
4✔
1087
                        }
1088
                        /*                                owner = ensureFamixPackageDefault();
1089
                        } else {*/
1090
                }
1091

1092
                // --------------- recover from name ?
1093
                if (owner != null) {
2✔
1094
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13✔
1095
                                if (matchAndMapClass(bnd, name, owner, candidate)) {
7✔
1096
                                        fmx = candidate;
2✔
1097
                                        break;
1✔
1098
                                }
1099
                        }
1✔
1100
                }
1101

1102
                // ---------------- create
1103
                if (fmx == null) {
2✔
1104
                        if (isGeneric) {
2✔
1105
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8✔
1106
                        }
1107
                        else {
1108
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7✔
1109
                                fmx.setTypeContainer((TWithTypes)owner);
4✔
1110
                        }
1111
                }
1112

1113
                // ---------------- modifiers and super-classes
1114
                if (fmx!=null) {
2!
1115
                        // we just created it, or it was not bound so we make sure it has the right information in it
1116
                        if (bnd != null) {
2✔
1117
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1118
                        }
1119

1120
                        TAssociation lastAssoc = null;
2✔
1121

1122
                        if (bnd != null) {
2✔
1123
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1124
                                if (supbnd != null) {
2✔
1125
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1126
                                }
1127
                                else {
1128
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8✔
1129
                                }
1130
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7✔
1131
                        }
1132
                }
1133

1134
                return fmx;
2✔
1135
        }
1136

1137
        /**
1138
         * Returns a Famix Exception associated with the ITypeBinding.
1139
         * The Entity is created if it does not exist.
1140
         * @param name -- the name of the Famix Exception
1141
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1142
         *
1143
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1144
         */
1145
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1146
                Exception fmx;
1147

1148
                // --------------- some special cases
1149
                if (bnd != null) {
2✔
1150
                        if (bnd.isArray()) {
3!
UNCOV
1151
                                bnd = bnd.getElementType();
×
1152
                        }
1153

1154
                        // for inner classes defined in generics !!! For others should not change anything
1155
                        bnd = bnd.getErasure();
3✔
1156
                }
1157

1158
                // ---------------- to avoid useless computations if we can
1159
                fmx = (Exception) getEntityByKey(bnd);
5✔
1160
                if (fmx != null) {
2✔
1161
                        return fmx;
2✔
1162
                }
1163

1164
                // --------------- name
1165
                if (name == null) {
2✔
1166
                        if (bnd == null) {
2!
UNCOV
1167
                                return null;  // not much we can do
×
1168
                        } else if (!bnd.isAnonymous()) {
3!
1169
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1170
                        } else { // anonymous class
UNCOV
1171
                                if (bnd.getSuperclass() != null) {
×
UNCOV
1172
                                        name = bnd.getSuperclass().getName();
×
1173
                                }
UNCOV
1174
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
UNCOV
1175
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
UNCOV
1176
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
UNCOV
1177
                                                name = bnd.getInterfaces()[0].getName();
×
1178
                                        }
1179
                                        else {
UNCOV
1180
                                                name = "???";
×
1181
                                        }
1182
                                }
UNCOV
1183
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1184
                        }
1185
                }
1186

1187
                // --------------- owner
1188
                if (owner == null) {
2✔
1189
                        if (bnd == null) {
2✔
1190
                                owner = ensureFamixPackageDefault();
4✔
1191
                        } else {
1192
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1193
                        }
1194
                }
1195

1196
                // --------------- recover from name ?
1197
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13✔
1198
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8!
UNCOV
1199
                                fmx = candidate;
×
UNCOV
1200
                                break;
×
1201
                        }
1202
                }
1✔
1203

1204
                // ---------------- create
1205
                if (fmx == null) {
2!
1206
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7✔
1207
                        fmx.setTypeContainer(owner);
3✔
1208
                }
1209

1210
        // we just created it or it was not bound, so we make sure it has the right information in it
1211
        TAssociation lastAssoc = null;
2✔
1212
        if (bnd != null) {
2✔
1213
            ITypeBinding supbnd = bnd.getSuperclass();
3✔
1214
            if (supbnd != null) {
2!
1215
                lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1216
            }
1217
            else {
1218
                lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
×
1219
            }
1220
            ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6✔
1221
        }
1222

1223
        return fmx;
2✔
1224
        }
1225

1226
        /**
1227
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1228
         * @param name -- the name of the FAMIX Method
1229
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1230
         * @return the FAMIX Class or null in case of a FAMIX error
1231
         */
1232
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1233
                Interface fmx;
1234

1235
                // --------------- some special cases
1236
                if (bnd != null) {
2!
1237
                        if (bnd.isArray()) {
3!
UNCOV
1238
                                bnd = bnd.getElementType();
×
1239
                        }
1240

1241
                        // for inner classes defined in generics !!! For others should not change anything
1242
                        bnd = bnd.getErasure();
3✔
1243
                }
1244

1245
                // ---------------- to avoid useless computations if we can
1246
                fmx = (Interface) getEntityByKey(bnd);
5✔
1247
                if (fmx != null) {
2✔
1248
                        return fmx;
2✔
1249
                }
1250

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

1274
                // --------------- owner
1275
                if (owner == null) {
2✔
1276
                        if (bnd == null) {
2!
1277
                                owner = ensureFamixPackageDefault();
×
1278
                        } else {
1279
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1280
                        }
1281
                }
1282

1283
                // --------------- recover from name ?
1284
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13✔
1285
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8✔
1286
                                fmx = candidate;
2✔
1287
                                break;
1✔
1288
                        }
1289
                }
1✔
1290

1291
                // ---------------- create
1292
                if (fmx == null) {
2✔
1293
                        if (isGeneric) {
2✔
1294
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7✔
1295
                        }
1296
                        else {
1297
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7✔
1298
                                fmx.setTypeContainer(owner);
3✔
1299
                        }
1300
                }
1301

1302
                // ---------------- modifiers and "super interfaces"
1303
                if (fmx!=null) {
2!
1304
                        // we just created it or it was not bound, so we make sure it has the right information in it
1305
                        if (bnd != null) {
2!
1306
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5✔
1307
                        }
1308
                        TAssociation lastAssociation = null;
2✔
1309
                        if (bnd != null) {
2!
1310
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6✔
1311
                        }
1312
                }
1313
                return fmx;
2✔
1314
        }
1315

1316
        /**
1317
         * "Converts" (if needed) a TTYpe entity to be a TThrowable. Might involve removing the existing entity, recreating a new one and migrating
1318
         * all the relationship of the former to the later
1319
         */
1320
        public TThrowable asException(TType fmxType) {
1321
                if (fmxType instanceof Exception) {
3✔
1322
                        return (Exception) fmxType;
3✔
1323
                }
1324
                if(fmxType instanceof TypeParameter) {
3✔
1325
                        return (TypeParameter) fmxType;
3✔
1326
                }
1327

1328
                Exception fmxException = null;
2✔
1329
                IBinding key;
1330

1331
                try {
1332
                        key = entityToKey.get(fmxType);
6✔
1333

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

1338
                        TWithTypes owner = fmxType.getTypeContainer();
3✔
1339
                        fmxType.setTypeContainer(null);
3✔
1340
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1341

1342
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8✔
1343
                        if (fmxType instanceof TWithAttributes) {
3!
1344
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8✔
1345
                        }
1346

1347
                        if (fmxType instanceof TWithInheritances) {
3!
1348
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8✔
1349
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8✔
1350
                        }
1351
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4✔
1352
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7✔
1353
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8✔
1354
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7✔
1355
                        fmxException.setIsStub(fmxType.getIsStub());
4✔
1356
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8✔
1357
                }
UNCOV
1358
                catch( ConcurrentModificationException e) {
×
UNCOV
1359
                        e.printStackTrace();
×
1360
                }
1✔
1361

1362
                return fmxException;
2✔
1363
        }
1364

1365
        /**
1366
         * helper method, we know the type exists, ensureFamixClass will recover it
1367
         */
1368
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1369
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1370
        }
1371

1372
        /**
1373
         * helper method, we know the type exists, ensureFamixInterface will recover it
1374
         */
1375
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1376
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1377
        }
1378

1379
        /**
1380
         * helper method, we know the type exists, ensureFamixInterface will recover it
1381
         */
1382
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1383
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1384
        }
1385

1386
        /**
1387
         * Ensures a famix entity for the owner of a binding.<br>
1388
         * This owner can be a method, a class or a namespace
1389
         * @param bnd -- binding for the owned entity
1390
         * @return a famix entity for the owner
1391
         */
1392
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1393
                TNamedEntity owner;
1394
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3✔
1395
                if (parentMtd != null) {
2✔
1396
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5✔
1397
                }
1398
                else {
1399
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3✔
1400
                        if (parentClass != null) {
2✔
1401
                owner = this.ensureFamixType(parentClass);
5✔
1402
            }
1403
                        else {
1404
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1405
                                if (parentPckg != null) {
2!
1406
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1407
                                } else {
UNCOV
1408
                                        owner = this.ensureFamixPackageDefault();
×
1409
                                }
1410
                        }
1411
                }
1412
                return owner;
2✔
1413
        }
1414

1415

1416
        /**
1417
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1418
         * We assume that PrimitiveType must be uniq for a given name
1419
         * @param name -- the name of the FAMIX PrimitiveType
1420
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1421
         */
1422
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1423
                if (name == null) {
2✔
1424
                        if (bnd == null) {
2!
UNCOV
1425
                                return null;
×
1426
                        } else {
1427
                                name = bnd.getName();
3✔
1428
                        }
1429
                }
1430
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7✔
1431
        }
1432

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

1436
                // --------------- to avoid useless computations if we can
1437
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1438
                if (fmx != null) {
2✔
1439
                        return fmx;
2✔
1440
                }
1441

1442
                // --------------- name
1443
                if (name == null) {
2✔
1444
                        if (bnd == null) {
2!
UNCOV
1445
                                return null;
×
1446
                        }
1447
                        else {
1448
                                name = bnd.getName();
3✔
1449
                        }
1450
                }
1451

1452
                // --------------- owner
1453
                if (owner == null) {
2✔
1454
                        if (bnd == null) {
2!
UNCOV
1455
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1456
                        } else {
1457
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1458
                        }
1459
                }
1460

1461
                // --------------- recover from name ?
1462
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1463
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
UNCOV
1464
                                fmx = candidate;
×
UNCOV
1465
                                break;
×
1466
                        }
UNCOV
1467
                }
×
1468

1469
                if (fmx == null) {
2!
1470
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1471
                        fmx.setTypeContainer(owner);
3✔
1472
                }
1473

1474
                if (bnd != null) {
2!
1475
                        setVisibility(fmx, bnd.getModifiers());
5✔
1476
                }
1477

1478
                return fmx;
2✔
1479
        }
1480

1481
        /**
1482
         * helper method, we know the type exists, ensureFamixEnum will recover it
1483
         */
1484
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1485
                return ensureFamixEnum(bnd, name, owner);
6✔
1486
        }
1487

1488
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1489
                EnumValue fmx;
1490

1491
                // --------------- to avoid useless computations if we can
1492
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1493
                if (fmx != null) {
2✔
1494
                        return fmx;
2✔
1495
                }
1496

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

1507
                // --------------- owner
1508
                if (owner == null) {
2✔
1509
                        if (bnd == null) {
2!
UNCOV
1510
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1511
                        }
1512
                        else {
1513
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1514
                        }
1515
                }
1516

1517
                // --------------- recover from name ?
1518
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
UNCOV
1519
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
UNCOV
1520
                                fmx = candidate;
×
1521
                                break;
×
1522
                        }
UNCOV
1523
                }
×
1524
                if (fmx == null) {
2!
1525
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1526
                        fmx.setParentEnum(owner);
3✔
1527
                }
1528

1529
        fmx.setParentEnum(owner);
3✔
1530

1531
        return fmx;
2✔
1532
        }
1533

1534
    /**
1535
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1536
         */
1537
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1538
                AnnotationType fmx;
1539

1540
                // --------------- to avoid useless computations if we can
1541
                fmx = (AnnotationType)getEntityByKey(bnd);
5✔
1542
                if (fmx != null) {
2✔
1543
                        return fmx;
2✔
1544
                }
1545

1546
                // --------------- name
1547
                if (name == null) {
2✔
1548
                        if (bnd == null) {
2!
UNCOV
1549
                                return null;
×
1550
                        }
1551
                        else {
1552
                                name = bnd.getName();
3✔
1553
                        }
1554
                }
1555

1556
                // --------------- owner
1557
                if (owner == null) {
2✔
1558
                        if (bnd == null) {
2!
UNCOV
1559
                                owner = ensureFamixPackageDefault();
×
1560
                        }
1561
                        else {
1562
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1563
                                if (parentPckg != null) {
2!
1564
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1565
                                } else {
UNCOV
1566
                                        owner = this.ensureFamixPackageDefault();
×
1567
                                }
1568
                        }
1569
                }
1570

1571
                // --------------- recover from name ?
1572
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1573
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1574
                                fmx = candidate;
2✔
1575
                                break;
1✔
1576
                        }
1577
                }
1✔
1578

1579
                // --------------- create
1580
                if (fmx == null) {
2✔
1581
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1582
                        fmx.setAnnotationTypesContainer(owner);
3✔
1583
                }
1584

1585
                if (bnd != null) {
2!
1586
                        // Not supported in Famix
1587

1588
                        // setVisibility(fmx, bnd.getModifiers());
1589
                }
1590

1591
                return fmx;
2✔
1592
        }
1593

1594
        /**
1595
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1596
         */
1597
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1598
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1599
        }
1600

1601
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1602
                AnnotationTypeAttribute fmx = null;
2✔
1603

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

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

1620
                // --------------- owner
1621
                if (owner == null) {
2!
UNCOV
1622
                        if (bnd == null) {
×
UNCOV
1623
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1624
                        }
1625
                        else {
UNCOV
1626
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
UNCOV
1627
                                if (parentType != null) {
×
UNCOV
1628
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1629
                                }
1630
                                else  {
1631
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1632
                                }
1633
                        }
1634
                }
1635

1636
                // --------------- recover from name ?
1637
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13✔
1638
                        // JDT treats annotation type attributes as methods ...
1639
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1640
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11!
1641
                                fmx = candidate;
×
UNCOV
1642
                                break;
×
1643
                        }
1644
                        // if the binding is null, the annotationTypeAttribute migth have been created
1645
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2!
1646
                                fmx = candidate;
×
UNCOV
1647
                                break;
×
1648
                        }
1649
                }
1✔
1650

1651
                if (fmx == null) {
2!
1652
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1653
                        fmx.setParentType(owner);
3✔
1654
                }
1655

1656
                if (bnd != null) {
2!
1657
                        // Not suopp
1658

1659
                        // setVisibility(fmx, bnd.getModifiers());
1660
                }
1661

1662
                return fmx;
2✔
1663
        }
1664

1665
        /**
1666
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1667
         */
1668
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1669
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6✔
1670
        }
1671
        
1672
        
1673
        /**
1674
         * Returns a FAMIX Wildcard with its bounds
1675
         * @param bnd
1676
         * @param name
1677
         * @param owner
1678
         * @return
1679
         */
1680
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1681
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8✔
1682
                if(bnd.getBound() != null) {
3✔
1683
                        Type bound = this.ensureFamixType(bnd.getBound());
5✔
1684
                        if(bnd.isUpperbound()) {
3✔
1685
                                fmx.setUpperBound(bound);
3✔
1686
                                bound.addUpperBoundedWildcards(fmx);
4✔
1687
                        }else{
1688
                                fmx.setLowerBound(bound);
3✔
1689
                                bound.addLowerBoundedWildcards(fmx);
3✔
1690
                        }
1691
                }
1692
                return fmx;
2✔
1693
        }
1694

1695
        /**
1696
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1697
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1698
         * @param name -- the name of the Famix TypeParameter
1699
         * @return the Famix TypeParameter or null in case of a Famix error
1700
         */
1701
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1702
                TypeParameter fmx;
1703

1704
                // --------------- to avoid useless computations if we can
1705
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1706
                if (fmx != null) {
2✔
1707
                        return fmx;
2✔
1708
                }
1709

1710
                // --------------- name
1711
                if (name == null) {
2✔
1712
                        if (bnd == null) {
2!
UNCOV
1713
                                return null;
×
1714
                        }
1715
                        else {
1716
                                name = bnd.getName();
3✔
1717
                        }
1718
                }
1719

1720
                // --------------- owner
1721
                if (owner == null && bnd != null) {
2!
UNCOV
1722
            if (bnd.getDeclaringClass() != null) {
×
UNCOV
1723
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
UNCOV
1724
            } else if(bnd.getDeclaringMethod() != null) {
×
UNCOV
1725
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1726
            }
1727
                }
1728

1729
                // --------------- recover from name ?
1730
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1731
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1732
                                fmx = (TypeParameter) candidate;
3✔
1733
                                break;
1✔
1734
                        }
1735
                }
1✔
1736

1737
                // --------------- create
1738
                if (fmx == null) {
2✔
1739
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1740
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1741
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5✔
1742
                                fmx.setUpperBound(upperBound);
3✔
1743
                        }
1744
                        if(bnd != null) {
2✔
1745
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
1746
                    Type upperBound = ensureFamixType(intbnd);
4✔
1747
                    fmx.setUpperBound(upperBound);
3✔
1748
                }
1749
            }
1750
                        fmx.setTypeContainer(owner);
3✔
1751
                }
1752

1753
                return fmx;
2✔
1754
        }
1755

1756
        /**
1757
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1758
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1759
         *
1760
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1761
         * @param name      of the package
1762
         * @param owner     of the package
1763
         * @param candidate -- a Famix Entity
1764
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1765
         */
1766
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1767
                if (!(candidate instanceof Package)) {
3!
UNCOV
1768
                        return false;
×
1769
                }
1770

1771
                // check whether bnd and candidate are already bound
1772
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1773
                if (res == CheckResult.MATCH) {
3✔
1774
                        return true;
2✔
1775
                } else if (res == CheckResult.FAIL) {
3!
UNCOV
1776
                        return false;
×
1777
                }
1778

1779
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1780
                        return false;
2✔
1781
                }
1782

1783
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1784
                conditionalMapToKey(bnd, candidate);
4✔
1785
                return true;
2✔
1786
        }
1787

1788
        /**
1789
         * Checks whether the existing unmapped Famix Type matches the binding.
1790
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1791
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1792
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1793
         * @param name of the type
1794
         * @param owner of the type
1795
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1796
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1797
         */
1798
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1799
                if (! (candidate instanceof Type) ) {
3!
UNCOV
1800
                        return false;
×
1801
                }
1802

1803
                // check whether bnd and candidate are already bound
1804
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1805
                if (res == CheckResult.MATCH) {
3✔
1806
                        return true;
2✔
1807
                }
1808
                else if (res == CheckResult.FAIL) {
3✔
1809
                        return false;
2✔
1810
                }
1811

1812
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
UNCOV
1813
                                bnd = bnd.getElementType();
×
1814
                }
1815

1816
                // checking names
1817
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
1818
                        name = bnd.getErasure().getName();
×
1819
                }
1820
                else if (bnd != null) {
2✔
1821
                        name = bnd.getName();
3✔
1822
                }
1823
                // else name = name
1824
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1825
                        return false;
2✔
1826
                }
1827

1828
                // special case of primitive types
1829
                if (candidate instanceof PrimitiveType) {
3!
UNCOV
1830
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1831
                                // names are equal so it's OK
UNCOV
1832
                                conditionalMapToKey(bnd, candidate);
×
UNCOV
1833
                                return true;
×
1834
                        }
UNCOV
1835
                        else if ( (bnd == null) && (owner == null) ) {
×
1836
                                return true;
×
1837
                        }
1838
                }
1839

1840
                // check owners without bnd
1841
                if (bnd == null) {
2✔
1842
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1843
                }
1844

1845
                // check owners with bnd
1846
                // type is an annotation
1847
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1848
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1849
                                conditionalMapToKey(bnd, candidate);
4✔
1850
                                return true;
2✔
1851
                        } else {
UNCOV
1852
                                return false;
×
1853
                        }
1854
                }
1855

1856
                // check owners with bnd
1857
                // type is a Parameterized type
1858
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
UNCOV
1859
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1860
                }
1861

1862
                // check owners with bnd
1863
                // type is an Enum
1864
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
UNCOV
1865
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1866
                }
1867

1868
                // check owners with bnd
1869
                // type is something elae (a class or interface)
1870
                // Annotation are interfaces too, so we should check this one after isAnnotation
1871
                if ( bnd.isClass()) {
3!
UNCOV
1872
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1873
                }
1874

1875
                if(bnd.isInterface()) {
3!
UNCOV
1876
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1877
                }
1878

1879
                return false;
2✔
1880
        }
1881

1882
        /**
1883
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1884
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1885
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1886
         * @param name of the class
1887
         * @param owner of the class
1888
         * @param candidate -- a Famix Entity
1889
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1890
         */
1891
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1892
                if (!(candidate instanceof Class)) {
3!
UNCOV
1893
                        return false;
×
1894
                }
1895

1896
                // check whether bnd and candidate are already bound
1897
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1898
                if (res == CheckResult.MATCH) {
3!
UNCOV
1899
                        return true;
×
1900
                } else if (res == CheckResult.FAIL) {
3✔
1901
                        return false;
2✔
1902
                }
1903

1904
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
1905
                        return false;
×
1906
                }
1907

1908
                // checking owner
1909
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1910
        }
1911

1912
        /**
1913
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1914
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1915
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1916
         * @param name of the class
1917
         * @param owner of the class
1918
         * @param candidate -- a Famix Entity
1919
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1920
         */
1921
        private boolean matchAndMapInterface(ITypeBinding bnd, String name, TNamedEntity owner, Type candidate) {
1922
                if (!(candidate instanceof Interface)) {
3!
1923
                        return false;
×
1924
                }
1925

1926
                // check whether bnd and candidate are already bound
1927
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1928
                if (res == CheckResult.MATCH) {
3!
UNCOV
1929
                        return true;
×
1930
                } else if (res == CheckResult.FAIL) {
3✔
1931
                        return false;
2✔
1932
                }
1933

1934
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
1935
                        return false;
×
1936
                }
1937

1938
                // checking owner
1939
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
1940
        }
1941

1942
        /**
1943
         * Checks whether the existing unmapped Famix "Method" matches the binding.
1944
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
1945
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
1946
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1947
         * @param sig -- signature of the method
1948
         * @param retTyp -- return type of the method
1949
         * @param owner of the method
1950
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
1951
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1952
         */
1953
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
1954
                if (! (candidate instanceof Method) ) {
3✔
1955
                        return false;
2✔
1956
                }
1957

1958
                // check whether bnd and candidate are already bound
1959
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1960
                if (res == CheckResult.MATCH) {
3!
UNCOV
1961
                        return true;
×
1962
                }
1963
                else if (res == CheckResult.FAIL) {
3✔
1964
                        return false;
2✔
1965
                }
1966

1967
                // checking names
1968
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
1969
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
1970
                        return false;
×
1971
                }
1972

1973
                // for methods, the name is not enough, we must test the signature also
1974
                // but not for AnnotationTypeAttribute
1975

1976
                        if (bnd != null) {
2✔
1977
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
1978
                        }
1979
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
1980
                                return false;
2✔
1981
                        }
1982

1983
                        // and still for method, must also check the return type
1984
                        if (bnd != null) {
2✔
1985
                                if (bnd.isConstructor()) {
3✔
1986
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4!
UNCOV
1987
                                                return false;
×
1988
                                        }
1989
                                        // else OK for now
1990
                                }
1991
                                else { // not a constructor
1992
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4!
UNCOV
1993
                                                return false;
×
1994
                                        }
1995
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10!
UNCOV
1996
                                                return false;
×
1997
                                        }
1998
                                        // else OK for now
1999
                                }
2000
                        }
2001
                        else {  // bnd == null
2002
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2!
2003
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4✔
2004
                                                return false;
2✔
2005
                                        }
2006
                                        // else OK for now
2007
                                } else { // (ret != null)  i.e. not a constructor
UNCOV
2008
                                        if (((Method) candidate).getDeclaredType() == null) {
×
UNCOV
2009
                                                return false;
×
UNCOV
2010
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
2011
                                                return false;
×
2012
                                        }
2013
                                        // else OK for now
2014
                                }
2015
                        }
2016

2017

2018
                // check owner
2019
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2020
                        conditionalMapToKey(bnd, candidate);
4✔
2021
                        return true;
2✔
2022
                } else {
2023
                        return false;
2✔
2024
                }
2025
        }
2026

2027
        /**
2028
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2029
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2030
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2031
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2032
         * @param name of the variable
2033
         * @param owner of the variable
2034
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2035
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2036
         */
2037
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2038
                if (!(candidate instanceof TStructuralEntity)) {
3!
UNCOV
2039
                        return false;
×
2040
                }
2041

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

2050
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
UNCOV
2051
                        return false;
×
2052
                }
2053

2054
                // check owner
2055
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2056

2057
                // local variable or parameter ?
2058
                // owner is a Method? (for example in case of an anonymous class)
2059
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11✔
2060
                if (res == CheckResult.FAIL) {
3✔
2061
                        return false;
2✔
2062
                } else if (res == CheckResult.MATCH) {
3!
2063
                        conditionalMapToKey(bnd, candidate);
×
UNCOV
2064
                        return true;
×
2065
                }
2066

2067
                // check owner
2068
                // <anArray>.length field?
2069
                if (name.equals("length")) {
4!
UNCOV
2070
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
UNCOV
2071
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
UNCOV
2072
                        if (isArrayLengthField) {
×
UNCOV
2073
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
UNCOV
2074
                                        conditionalMapToKey(bnd, candidate);
×
UNCOV
2075
                                        return true;
×
2076
                                }
2077
                                else {
UNCOV
2078
                                        return false;
×
2079
                                }
2080
                        }
2081
                }
2082

2083
                // check owner
2084
                // "normal" field?
2085
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2086
                if (res == CheckResult.MATCH) {
3!
2087
                        conditionalMapToKey(bnd, candidate);
4✔
2088
                        return true;
2✔
2089
                }
2090
                return false;
×
2091
        }
2092

2093
        /**
2094
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2095
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2096
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2097
         * @param owner -- the owner of the type
2098
         * @param candidate -- a Famix Entity
2099
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2100
         */
2101
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2102
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4✔
2103

2104
                // owner is a Method? (for example in case of an anonymous class)
2105
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2106
                if (res == CheckResult.MATCH) {
3!
UNCOV
2107
                        conditionalMapToKey(bnd, candidate);
×
2108
                        return true;
×
2109
                } else if (res == CheckResult.FAIL) {
3!
UNCOV
2110
                        return false;
×
2111
                }
2112

2113
                // owner is a class ?
2114
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2115
                if (res == CheckResult.MATCH) {
3✔
2116
                        conditionalMapToKey(bnd, candidate);
4✔
2117
                        return true;
2✔
2118
                }
2119
                else if (res == CheckResult.FAIL) {
3✔
2120
                        return false;
2✔
2121
                }
2122

2123
                // owner must be a package
2124
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2125
                        conditionalMapToKey(bnd, candidate);
4✔
2126
                        return true;
2✔
2127
                }
2128
                return false;
2✔
2129
        }
2130

2131
        /**
2132
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2133
         * @param methBnd
2134
         * @param owner
2135
         * @param candidateOwner
2136
         * @return a {@link CheckResult}
2137
         */
2138
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2139
                if ((methBnd != null) || (owner instanceof Method)) {
5!
2140
                        if (!(candidateOwner instanceof Method)) {
3!
UNCOV
2141
                                return CheckResult.FAIL;
×
2142
                        }
2143

2144
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2145
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2146
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2147

2148
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
UNCOV
2149
                                return CheckResult.MATCH;
×
2150
                        } else {
2151
                                return CheckResult.FAIL;
2✔
2152
                        }
2153
                }
2154
                return CheckResult.UNDECIDED;
2✔
2155
        }
2156

2157
        /**
2158
         * @param typBnd
2159
         * @param owner
2160
         * @param candidateOwner
2161
         * @return a {@link CheckResult}
2162
         */
2163
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2164
                if ((typBnd != null) || (owner instanceof Type)) {
5✔
2165
                        if (!(candidateOwner instanceof Type)) {
3✔
2166
                                return CheckResult.FAIL;
2✔
2167
                        }
2168

2169
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2170
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2171

2172
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2173
                                return CheckResult.MATCH;
2✔
2174
                        } else {
2175
                                return CheckResult.FAIL;
2✔
2176
                        }
2177
                }
2178
                return CheckResult.UNDECIDED;
2✔
2179
        }
2180

2181
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2182
                if ((pckgBnd != null) || (owner instanceof Package)) {
5!
2183
                        if (!(candidateOwner instanceof Package)) {
3!
UNCOV
2184
                                return CheckResult.FAIL;
×
2185
                        }
2186

2187
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2188
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2189

2190
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2191
                                return CheckResult.MATCH;
2✔
2192
                        } else {
2193
                                return CheckResult.FAIL;
2✔
2194
                        }
2195
                }
UNCOV
2196
                return CheckResult.UNDECIDED;
×
2197
        }
2198

2199
        /**
2200
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2201
         * 'name' and 'bnd' cannot be null together
2202
         * @param bnd -- binding associated with the entity may be null
2203
         * @param name -- name of the entity may be null
2204
         * @param candidate
2205
         * @return true if names match, false if not
2206
         */
2207
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2208
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8!
UNCOV
2209
                        return CheckResult.FAIL;
×
2210
                }
2211
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9!
2212
                        return CheckResult.FAIL;
2✔
2213
                }
2214
                else {
2215
                        return CheckResult.MATCH;
2✔
2216
                }
2217
        }
2218

2219
        /**
2220
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2221
         * @param key
2222
         * @param candidate
2223
         * @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>
2224
         */
2225
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2226
                if (key == null) {
2✔
2227
                        return CheckResult.UNDECIDED;
2✔
2228
                }
2229

2230
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2231
                if (bound == candidate) {
3✔
2232
                        return CheckResult.MATCH;
2✔
2233
                }
2234
                else if (bound != null) {
2✔
2235
                        return CheckResult.FAIL;
2✔
2236
                }
2237
                else if (getEntityKey(candidate) != null) {
4✔
2238
                        // candidate already bound, and not to this binding
2239
                        return CheckResult.FAIL;
2✔
2240
                }
2241
                else {
2242
                        return CheckResult.UNDECIDED;
2✔
2243
                }
2244
        }
2245

2246
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2247
                if (bnd != null) {
2✔
2248
                        mapEntityToKey(bnd, ent);
4✔
2249
                }
2250
        }
1✔
2251

2252
        public Method ensureFamixMethod(IMethodBinding bnd) {
2253
                return ensureFamixMethod(
8✔
2254
                                bnd,
2255
                                /*name*/null,
2256
                                /*paramsType*/null,
2257
                                /*returnType*/null,
2258
                                /*owner*/null,
2259
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2260
        }
2261

2262
        /**
2263
         * Returns a Famix Method associated with the IMethodBinding. The Entity is created if it does not exist.
2264
         * The Entity is created if it does not exist.
2265
         * @param name -- the name of the Famix Method (MUST NOT be null, but this is not checked)
2266
         * @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)
2267
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2268
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2269
         */
2270
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, Type ret, TWithMethods owner, int modifiers) {
2271
                Method fmx;
2272
                String signature;
2273
                boolean delayedRetTyp;
2274

2275
                // --------------- to avoid useless computations if we can
2276
                fmx = (Method)getEntityByKey(bnd);
5✔
2277
                if (fmx != null) {
2✔
2278
                        return fmx;
2✔
2279
                }
2280

2281
                // --------------- name
2282
                if (name == null) {
2✔
2283
                        if (bnd == null) {
2✔
2284
                                return null;
2✔
2285
                        }
2286
                        else {
2287
                                name = bnd.getName();
3✔
2288
                        }
2289
                }
2290

2291
                // --------------- signature
2292
                signature = name + "(";
3✔
2293
                 if (bnd != null) {
2✔
2294
                    signature += signatureParamsFromBinding(bnd);
7✔
2295
                }
2296
        else if (paramTypes != null) {
2!
2297
                        signature += signatureParamsFromStringCollection(paramTypes);
7✔
2298
                }
2299
                else {
UNCOV
2300
                        signature += "???";
×
2301
                }
2302
                signature += ")";
3✔
2303

2304
                // --------------- return type
2305
                delayedRetTyp = false;
2✔
2306
                ITypeBinding retTypBnd = null;
2✔
2307
                if (ret == null) {
2!
2308
                        if (bnd != null) {
2✔
2309
                // must create the return type
2310
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2311
                // we need T to create the method and the method to create T ...
2312
                // so we need to test the situation and deal with it
2313
                retTypBnd = bnd.getReturnType();
3✔
2314
                if (retTypBnd != null) {
2✔
2315
                    if (retTypBnd.isArray()) {
3✔
2316
                        retTypBnd = retTypBnd.getElementType();
3✔
2317
                    }
2318
                }
2319

2320
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2321
                    delayedRetTyp = true;
3✔
2322
                }
2323
                else {
2324
                    ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2325
                }
2326
                        }
2327
                }
2328

2329
                // --------------- owner
2330
                if (owner == null) {
2✔
2331
                        if (bnd == null) {
2✔
2332
                                owner = ensureFamixClassStubOwner();
4✔
2333
                        }
2334
                        else {
2335
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2336
                                if (classBnd != null) {
2!
2337
                                        owner = ensureFamixType(classBnd);
5✔
2338
                                }
2339
                                else {
UNCOV
2340
                                        owner = ensureFamixClassStubOwner();
×
2341
                                }
2342
                        }
2343
                }
2344

2345
                // --------------- recover from name ?
2346
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2347
                        if (matchAndMapMethod(bnd, signature, ret, (TNamedEntity) owner, candidate)) {
9✔
2348
                                fmx = candidate;
2✔
2349
                                break;
1✔
2350
                        }
2351
                }
1✔
2352

2353
                if (fmx == null) {
2✔
2354
                        if(bnd != null && bnd.isGenericMethod()) {
5✔
2355
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7✔
2356
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18✔
2357
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6✔
2358
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4✔
2359
                                }
2360
                        // Parameterized method binding = when the method is the target of an invocation.
2361
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5!
UNCOV
2362
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
×
2363
                        } else {
2364
                if (bnd != null && bnd.isConstructor()) {
5✔
2365
                    fmx = ensureFamixEntity(Initializer.class, bnd, name);
8✔
2366
                } else {
2367
                    fmx = ensureFamixEntity(Method.class, bnd, name);
7✔
2368
                }
2369
            }
2370

2371
                        fmx.setSignature(signature);
3✔
2372
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7✔
2373
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6✔
2374
                        fmx.setParentType(owner);
3✔
2375
                }
2376

2377
                if (fmx != null) {
2!
2378
                        setMethodModifiers(fmx, modifiers);
4✔
2379
                }
2380

2381
        //If it has the #default keywork, we mark it as default implementation
2382
        if (Modifier.isDefault(modifiers)) {
3✔
2383
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3✔
2384
        }
2385

2386
        if (delayedRetTyp) {
2✔
2387
                        int retTypModifiers = retTypBnd.getModifiers();
3✔
2388
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3✔
2389
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2390
                }
2391

2392
                return fmx;
2✔
2393
        }
2394

2395

2396
        /**
2397
         * Creates or recovers the initializer method containing the attribute initializations of a type.
2398
         * @param owner Type containing the initializer
2399
         * @param isStatic Modifier of the initializer. A type can have 2 initializers for attribute initialization: 1 static and 1 not.
2400
         * @param isInitializationBlock True if the entity is an initialization block. False for the artificial method containing all field initializations.
2401
         * @return the FamixInitializer
2402
         */
2403
        public Initializer ensureFamixInitializer(TWithMethods owner, Boolean isStatic, Boolean isInitializationBlock) {
2404
                Initializer fmx = null;
2✔
2405

2406
                if (owner != null) {
2!
2407
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
6✔
2408
                                        .filter(meth ->
1✔
2409
                                                        ((Method) meth).getIsInitializer() &&
8✔
2410
                                                        ((Method) meth).getIsConstructor().equals(false) &&
7✔
2411
                                                        ((Method) meth).getIsClassSide().equals(isStatic) &&
6✔
2412
                                                        ((Initializer) meth).getIsInitializationBlock().equals(isInitializationBlock))
7✔
2413
                                        .findFirst();
2✔
2414
                        if (existingInitializer.isPresent()) {
3✔
2415
                                fmx = (Initializer) existingInitializer.get();
4✔
2416
                        }
2417
                }
2418

2419
                if (fmx == null) {
2✔
2420
                        fmx = new Initializer();
4✔
2421
                        fmx.setName(INIT_BLOCK_NAME);
3✔
2422
                        fmx.setSignature(INIT_BLOCK_NAME + "()" );
3✔
2423
                        fmx.setVisibility(MODIFIER_PRIVATE);
3✔
2424
                        fmx.setParentType(owner);
3✔
2425
                        fmx.setIsClassSide(isStatic);
3✔
2426
                        fmx.setIsInitializationBlock(isInitializationBlock);
3✔
2427
                }
2428

2429
                return fmx;
2✔
2430
        }
2431

2432

2433
        public Initializer ensureImplicitConstructor(TWithMethods owner, String name, Collection<String> parameterTypesNames) {
2434
                Initializer fmx = null;
2✔
2435

2436
                if (owner != null) {
2!
2437
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
5✔
2438
                                        .filter(meth ->
1✔
2439
                                                        ((Method) meth).getIsInitializer() &&
8✔
2440
                                                                        ((Method) meth).getIsConstructor()
4✔
2441
                                                                        && meth.getParameters().size() == parameterTypesNames.size()
6✔
2442
                                                                        && (parameterTypesNames.stream().allMatch(parameterName -> meth.getSignature().contains(parameterName))) )
13!
2443
                                        .findFirst();
2✔
2444
                        if (existingInitializer.isPresent()) {
3✔
2445
                                fmx = (Initializer) existingInitializer.get();
4✔
2446
                        }
2447
                }
2448

2449
                if (fmx == null) {
2✔
2450
                        fmx = ensureFamixEntity(Initializer.class, null, name);
7✔
2451
                        fmx.setParentType(owner);
3✔
2452
                        fmx.setSignature(name + "()");
4✔
2453

2454
                }
2455

2456
                return fmx;
2✔
2457
        }
2458

2459
        /**
2460
         * Creates or recovers a stub Famix Method
2461
         * @param name of the method
2462
         * @return the Famix Method
2463
         */
2464
        public Method ensureFamixStubMethod(String name) {
UNCOV
2465
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2466
        }
2467

2468
        public void setAttributeModifiers(Attribute fmx, int mod) {
2469
                setCommonModifiers(fmx, mod);
4✔
2470
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2471
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2472
        }
1✔
2473

2474
        public void setMethodModifiers(Method fmx, int mod) {
2475
                setCommonModifiers(fmx, mod);
4✔
2476
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2477
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2478
        }
1✔
2479

2480
        public void setClassModifiers(Class fmx, int mod) {
2481
                setCommonModifiers(fmx, mod);
4✔
2482
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2483
        }
1✔
2484

2485
        public void setInterfaceModifiers(Interface fmx, int mod) {
2486
                setCommonModifiers(fmx, mod);
4✔
2487
        }
1✔
2488

2489
        private void setCommonModifiers(Entity fmx, int mod) {
2490
                setVisibility((THasVisibility)fmx, mod);
5✔
2491
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2492
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2493
        }
1✔
2494

2495
        /**
2496
         * Sets the visibility of a FamixNamedEntity
2497
         *
2498
         * @param fmx -- the FamixNamedEntity
2499
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2500
         */
2501
        public void setVisibility(THasVisibility fmx, int mod) {
2502
                if (Modifier.isPublic(mod)) {
3✔
2503
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2504
                } else if (Modifier.isPrivate(mod)) {
3✔
2505
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2506
                } else if (Modifier.isProtected(mod)) {
3✔
2507
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2508
                } else {
2509
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2510
                }
2511
        }
1✔
2512

2513
        /**
2514
         * Returns a Famix Attribute associated with the IVariableBinding.
2515
         * The Entity is created if it does not exist.<br>
2516
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2517
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2518
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2519
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2520
         */
2521
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2522
                Attribute fmx;
2523

2524
                // --------------- to avoid useless computations if we can
2525
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2526
                if (fmx != null) {
2✔
2527
                        return fmx;
2✔
2528
                }
2529

2530
                // --------------- name
2531
                if (name == null) {
2!
UNCOV
2532
                        if (bnd == null) {
×
UNCOV
2533
                                return null;
×
2534
                        }
2535
                        else {
UNCOV
2536
                                name = bnd.getName();
×
2537
                        }
2538
                }
2539

2540
                // --------------- owner
2541
                if (owner == null) {
2✔
2542
                        if (bnd == null) {
2!
UNCOV
2543
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2544
                        }
2545
                        else {
2546
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2547
                                        // Declaring class is the generic one if the class is parametric.
2548
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2549
                                } else {
2550
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2551
                                }
2552
                        }
2553
                }
2554

2555
                // --------------- recover from name ?
2556
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2557
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2558
                                fmx = candidate;
2✔
2559
                                break;
1✔
2560
                        }
2561
                }
1✔
2562

2563
                if (fmx == null) {
2✔
2564
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2565
                        fmx.setParentType( owner);
3✔
2566
                }
2567

2568
        fmx.setParentType(owner);
3✔
2569
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2570
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2571
        if (bnd != null) {
2✔
2572
            int mod = bnd.getModifiers();
3✔
2573
            setAttributeModifiers(fmx, mod);
4✔
2574
        }
2575

2576
        return fmx;
2✔
2577
        }
2578

2579
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2580
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2581
        }
2582

2583
        /**
2584
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2585
         */
2586
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2587
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2588
        }
2589

2590
        /**
2591
         * Returns a Famix Parameter associated with the IVariableBinding.
2592
         * The Entity is created if it does not exist.<br>
2593
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2594
         */
2595
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2596
                Parameter fmx = null;
2✔
2597

2598
                // --------------- to avoid useless computations if we can
2599
                try {
2600
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
UNCOV
2601
                }catch(Throwable e) {
×
UNCOV
2602
                        e.printStackTrace();
×
2603
                }
1✔
2604
                if (fmx != null) {
2✔
2605
                        return fmx;
2✔
2606
                }
2607

2608
                // --------------- name
2609
                if (name == null) {
2!
UNCOV
2610
                        if (bnd == null) {
×
UNCOV
2611
                                return null;
×
2612
                        }
2613
                        else {
UNCOV
2614
                                name = bnd.getName();
×
2615
                        }
2616
                }
2617

2618
                // --------------- owner
2619
                if (tMethod == null) {
2!
2620
                        if (bnd == null) {
×
UNCOV
2621
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2622
                        }
2623
                        else {
UNCOV
2624
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2625
                        }
2626
                }
2627

2628
                // --------------- recover from name ?
2629
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2630
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
UNCOV
2631
                                fmx = candidate;
×
2632
                                break;
×
2633
                        }
2634
                }
1✔
2635

2636
                if (fmx == null) {
2!
2637
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2638
                }
2639

2640
                if (fmx != null) {
2!
2641
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2642
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2643
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2644
                }
2645

2646
                return fmx;
2✔
2647
        }
2648

2649
    /**
2650
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2651
         * The Entity is created if it does not exist.<br>
2652
         * @param name -- the name of the FAMIX LocalVariable
2653
         * @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
2654
         */
2655
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2656
                LocalVariable fmx;
2657

2658
                // --------------- to avoid useless computations if we can
2659
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2660
                if (fmx != null) {
2!
UNCOV
2661
                        return fmx;
×
2662
                }
2663

2664
                // --------------- name
2665
                if (name == null) {
2!
UNCOV
2666
                        if (bnd == null) {
×
UNCOV
2667
                                return null;
×
2668
                        }
2669
                        else {
UNCOV
2670
                                name = bnd.getName();
×
2671
                        }
2672
                }
2673

2674
                // --------------- owner
2675
                if (owner == null) {
2!
UNCOV
2676
                        if (bnd == null) {
×
UNCOV
2677
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2678
                        }
2679
                        else {
UNCOV
2680
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2681
                        }
2682
                }
2683

2684
                // --------------- recover from name ?
2685
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2686
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
UNCOV
2687
                                fmx = candidate;
×
2688
                                break;
×
2689
                        }
2690
                }
1✔
2691

2692
                if (fmx == null) {
2!
2693
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2694
                        fmx.setParentBehaviouralEntity(owner);
3✔
2695
                }
2696

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

2700
        return fmx;
2✔
2701
        }
2702

2703
    /**
2704
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2705
         * If this ImplicitVariable does not exist yet, it is created
2706
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2707
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2708
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2709
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2710
         */
2711
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2712
                ImplicitVariable fmx;
2713
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7✔
2714
                fmx.setParentBehaviouralEntity(tMethod);
3✔
2715
                return fmx;
2✔
2716
        }
2717

2718
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2719
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2720
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2721
        }
2722

2723
        /**
2724
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2725
         * @param jCmt -- the content (String) of the comment 
2726
         * @param owner -- the entity that is commented
2727
         * @return the Famix Comment
2728
         */
2729
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2730
                Comment cmt = null;
2✔
2731

2732
                if ( (jCmt != null) && (owner != null) ) {
4!
2733
                        
2734
                        cmt = new Comment();
4✔
2735
                        addSourceAnchor(cmt, jCmt);
5✔
2736
                        famixRepoAdd(cmt);
3✔
2737
                        cmt.setCommentedEntity(owner);
3✔
2738
                }
2739

2740
                return cmt;
2✔
2741
        }
2742

2743
        /**
2744
         * Creates and returns a Famix Comment and associates it with an Entity
2745
         * @param jCmt -- the content (String) of the comment 
2746
         * @param owner -- the entity that is commented
2747
         * @param content -- the text of the comment
2748
         * @return the Famix Comment
2749
         */
2750
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2751
                Comment cmt = null;
2✔
2752

2753
                if ( (jCmt != null) && (owner != null) ) {
4!
2754
                        cmt = new Comment();
4✔
2755
                        cmt.setContent(content );
3✔
2756
                        famixRepoAdd(cmt);
3✔
2757
                        cmt.setCommentedEntity(owner);
3✔
2758
                }
2759

2760
                return cmt;
2✔
2761
        }
2762

2763
        /**
2764
         * Adds location information to a Famix Entity.
2765
         * 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.
2766
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2767
         * @param fmx -- Famix Entity to add the anchor to
2768
         * @param node -- JDT ASTNode, where the information is extracted
2769
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2770
         */
2771
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2772
                IndexedFileAnchor fa;
2773

2774
                fa = createIndexedFileAnchor(node);
4✔
2775
                if ((fmx != null) && (fa != null)) {
4!
2776
                        fmx.setSourceAnchor(fa);
3✔
2777
                        famixRepoAdd(fa);
3✔
2778
                }
2779

2780
                return fa;
2✔
2781
        }
2782

2783
        /**
2784
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2785
         */
2786
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2787
                IndexedFileAnchor fa;
2788

2789
                fa = createIndexedFileAnchor(node);
4✔
2790
                if ((fmx != null) && (fa != null)) {
4!
2791

2792
                        // may change the positions
2793
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2794
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2795
                        if (node.getName() != null) {
3!
2796
                                methodDeclarationModifiers.add(node.getName());
5✔
2797
                        }
2798
                        if (node.getReturnType2() != null) {
3✔
2799
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2800
                        }
2801
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2802
                        int end = node.getStartPosition() + node.getLength();
6✔
2803

2804
                        fa.setStartPos(beg);
4✔
2805
                        fa.setEndPos(end);
4✔
2806

2807
                        fmx.setSourceAnchor(fa);
3✔
2808
                        famixRepoAdd(fa);
3✔
2809
                }
2810

2811
                return fa;
2✔
2812
        }
2813

2814
        /**
2815
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2816
         * Information returned in the form of an IndexedFileAnchor
2817
         */
2818
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2819
                IndexedFileAnchor fa;
2820
                
2821
                if (node == null) {
2!
UNCOV
2822
                        return null;
×
2823
                }
2824

2825
                // position in source file
2826
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2827
                int end = beg + node.getLength() - 1;
7✔
2828

2829
                // find source Compilation Unit
2830
                // there is a special case for the JDT Comment Nodes
2831
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2832
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2833
                } else {
2834
                        node = node.getRoot();
3✔
2835
                }
2836

2837
                fa = new IndexedFileAnchor();
4✔
2838
                fa.setStartPos(beg);
4✔
2839
                fa.setEndPos(end);
4✔
2840

2841
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6✔
2842

2843
                return fa;
2✔
2844
        }
2845

2846
        /**
2847
         * Creates or recovers the Famix Class for "Object".
2848
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2849
         *
2850
         * @return a Famix class for "Object"
2851
         */
2852
        public Class ensureFamixClassObject() {
2853
        // 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...
2854
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5✔
2855

2856
        for (Class entity : objects) {
10✔
2857
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2858
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7✔
2859
                    return entity;
2✔
2860
                }
2861
        }
1✔
2862

2863
        Class fmx = createFamixEntity(Class.class, "Object");
6✔
2864
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2865
                return fmx;
2✔
2866
        }
2867

2868
        /**
2869
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2870
         */
2871
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2872
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2873
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2874

2875
                if (fmx != null) {
2!
2876
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2877
                }
2878

2879
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
UNCOV
2880
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
2881
                }
2882

2883
                return fmx;
2✔
2884
        }
2885

2886
        public Class getFamixMetaClass(ITypeBinding bnd) {
2887
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2888
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2889
        }
2890

2891
        /**
2892
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
2893
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
2894
         * JDT does not create a binding for these classes, so we create a stub one here.
2895
         *
2896
         * @return a Famix class
2897
         */
2898
        public Class ensureFamixClassArray() {
UNCOV
2899
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
UNCOV
2900
                if (fmx != null) {
×
UNCOV
2901
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
×
UNCOV
2902
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
2903

2904
                        // may be not needed anymore now that we use modifiers
2905
                        /*fmx.setIsAbstract(Boolean.FALSE);
2906
                        fmx.setIsFinal(Boolean.FALSE);
2907
                        fmx.setIsInterface(Boolean.FALSE); 
2908
                        fmx.setIsPrivate(Boolean.FALSE);
2909
                        fmx.setIsProtected(Boolean.FALSE);*/
UNCOV
2910
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2911
                }
2912

UNCOV
2913
                return fmx;
×
2914
        }
2915

2916
        public String removeLastPartOfPackageName(String qualifiedName) {
2917
                String ret;
2918
                int last = qualifiedName.lastIndexOf('.');
4✔
2919
                if (last > 0) {
2✔
2920
                        // recursively creating the parent
2921
                        ret = qualifiedName.substring(0, last);
6✔
2922
                }
2923
                else {
2924
                        ret = "";
2✔
2925
                }
2926

2927
                return ret;
2✔
2928
        }
2929

2930
        /** Generates the list of parameters for a method signature
2931
         * @return a string
2932
         */
2933
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2934
                boolean first = true;
2✔
2935
                String sig = "";
2✔
2936

2937
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2938
                        if (first) {
2✔
2939
                                sig = parBnd.getName();
3✔
2940
                                first = false;
3✔
2941
                        }
2942
                        else {
2943
                                sig += "," + parBnd.getName();
5✔
2944
                        }
2945
                }
2946
                return sig;
2✔
2947
        }
2948

2949
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2950
                boolean first = true;
2✔
2951
                String sig = "";
2✔
2952

2953
                for (String t : paramTypes) {
10✔
2954
                        if (first) {
2✔
2955
                                sig = t;
2✔
2956
                                first = false;
3✔
2957
                        }
2958
                        else {
2959
                                sig += "," + t;
4✔
2960
                        }
2961
                }
1✔
2962
                return sig;
2✔
2963
        }
2964

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