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

moosetechnology / VerveineJ / 14660115829

25 Apr 2025 08:16AM UTC coverage: 50.58% (+0.6%) from 49.972%
14660115829

Pull #127

github

web-flow
Merge 56b1c8e73 into 5207a6c7c
Pull Request #127: New generics implementation

1876 of 3946 branches covered (47.54%)

Branch coverage included in aggregate %.

486 of 1087 new or added lines in 52 files covered. (44.71%)

56 existing lines in 10 files now uncovered.

4270 of 8205 relevant lines covered (52.04%)

2.08 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

153

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

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

174
        /**
175
         * Resets the dictionnary in a proper state after loading entities from an existing MSE file:
176
         * <UL>
177
         * <li>map all named entities to their names in <b>mapName</b></li>
178
         * <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>
179
         * </ul>
180
         */
181
        protected void recoverExistingRepository() {
182
                for (NamedEntity ent : famixRepo.all(NamedEntity.class)) {
13✔
183
                        mapEntityToName( ent.getName(), ent);
5✔
184
                        // for the Exception to be raised, the return value must be tested
185
                        try { if (((TCanBeStub) ent).getIsStub()) {} }
5✔
186
                        catch (NullPointerException e) { ((TCanBeStub)ent).setIsStub(Boolean.FALSE); }
6✔
187
                }
1✔
188

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

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

206
        public void removeEntity( NamedEntity ent) {
207
                IBinding key;
208
                key = entityToKey.get(ent);
6✔
209
                entityToKey.remove(ent);
5✔
210
                keyToEntity.remove(key);
5✔
211

212
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7✔
213
                l_ent.remove(ent);
4✔
214

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

246
                return ret;
2✔
247
        }
248

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

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

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

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

302
                        mapEntityToName(name, fmx);
4✔
303
                        
304
                        // put new entity in Famix repository
305
                        famixRepoAdd((Entity) fmx);
4✔
306
                }
307

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

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

354

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

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

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

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

427
        ///// ensure Famix Relationships /////
428

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

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

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

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

475
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6!
476
                        TConcreteType concreteType = (TConcreteType)ensureFamixType(concreteIterator.next());
7✔
477
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7✔
478

479
                        Concretization concretization = ensureFamixConcretization(concreteType, typeParameter);
5✔
480
                        association.addConcretization(concretization);                                
3✔
481
                }
1✔
482

483
                return association;
2✔
484
        }
485

486
        /**
487
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
488
         * @param concreteType -- the concrete type
489
         * @param typeParameter -- the generic type parameter
490
         * @return the Concretization relationship
491
         */
492
        public Concretization ensureFamixConcretization(TConcreteType concreteType, TypeParameter typeParameter ) {
493
                if ( (concreteType == null) || (typeParameter == null) ) {
4!
UNCOV
494
                        return null;
×
495
                }
496

497
                Concretization concretization = new Concretization();
4✔
498
                concretization.setConcreteParameter(concreteType);
3✔
499
                concretization.setGenericParameter(typeParameter);
3✔
500

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

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

530
                implementation.setImplementingClass(implementingClass);
3✔
531
                implementation.setMyInterface(myInterface);
3✔
532
                chainPrevNext(prev, implementation);
4✔
533
                famixRepoAdd(implementation);
3✔
534
                return implementation;
2✔
535
        }
536

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

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

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

577
                Reference ref = new Reference();
4✔
578
                ref.setReferredEntity(tgt);
3✔
579
                ref.setReferencer(src);
3✔
580
                chainPrevNext(prev,ref);
4✔
581
                famixRepoAdd(ref);
3✔
582

583
                return ref;
2✔
584
        }
585

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

608
                invocation.setReceiver(receiver);
3✔
609
                invocation.setSender(tMethod);
3✔
610
                invocation.setSignature((signature == null) ? invoked.getSignature() : signature);
5!
611
                invocation.addCandidates(invoked);
3✔
612
                chainPrevNext(prev,invocation);
4✔
613
                famixRepoAdd(invocation);
3✔
614
                
615
                return invocation;
2✔
616
        }
617

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

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

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

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

702

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

726

727
        ///// Special Case: ImplicitVariables /////
728

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

762
                return ret;
×
763
        }
764

765
        ///// Special Case: "Uniq" Entities /////
766

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

804
                return fmx;
2✔
805
        }
806

807
        /**
808
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
809
         *
810
         * @return a Famix class
811
         */
812
        public Class ensureFamixClassStubOwner() {
813
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7✔
814
                if (fmx != null) {
2!
815
                        fmx.setTypeContainer( ensureFamixPackageDefault());
4✔
816
                }
817
                ensureFamixInheritance(ensureFamixClassObject(null), fmx, /*prev*/null, null);
9✔
818

819
                return fmx;
2✔
820
        }
821

822
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
823
                if (ctxt == null) {
×
824
                        return null;
×
825
                }
826
                
827
                for (TType candidate : ctxt.getTypes()) {
×
828
                        if (((TNamedEntity)candidate).getName().equals(name) ) {
×
829
                                return (Type) candidate;
×
830
                        }
831
                }
×
832
                
833
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
834
        }
835

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

851
                if ((name == null) && (bnd != null)) {
4!
852
                        name = bnd.getName();
3✔
853
                }
854

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

873
                return fmx;
2✔
874
        }
875

876
        /**
877
         * Creates or recovers a default Famix Package.
878
         * Because this package does not really exist, it has no binding.
879
         *
880
         * @return a Famix Namespace
881
         */
882
        public Package ensureFamixPackageDefault() {
883
                Package fmx = ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7✔
884

885
                return fmx;
2✔
886
        }
887

888
        /**
889
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
890
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
891
         *
892
         * @param bnd -- a potential binding for the "java.lang" package
893
         * @return a Famix Namespace for "java.lang"
894
         */
895
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
896
                Package fmx = this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5✔
897

898
                return fmx;
2✔
899
        }
900

901
        /**
902
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
903
         */
904
        public Package getFamixPackageDefault() {
905
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5✔
906
                if (l.size() > 0) {
3!
907
                        return l.iterator().next();
5✔
908
                } else {
909
                        return null;
×
910
                }
911
        }
912

913
        /**
914
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
915
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
916
         * @param bnd -- binding for the type to create
917
         * @param name of the type
918
         * @param owner of the type
919
         * @param ctxt -- context of use of the type
920
         */
921
        public TType ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
922
                
923
                TType fmx = null;
2✔
924

925
                if (bnd == null) {
2✔
926
                        if (name == null) {
2!
927
                                return null;
2✔
928
                        }
929
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
930
                        if (fmx != null) {
×
931
                                return fmx;
×
932
                        }
933

934
                        if ( (owner != null) && (owner instanceof TParametricEntity) ) {
×
NEW
935
                                return this.ensureFamixTypeParameter(null, name, owner);
×
936
                        }
937
                        else {
938
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
939
                                fmx.setTypeContainer(owner);
×
940
                                return fmx;
×
941
                        }
942
                }
943

944
                // bnd != null
945

946
                fmx = (TType) getEntityByKey(bnd);
5✔
947
                if (fmx != null) {
2✔
948
                        return fmx;
2✔
949
                }
950

951
                if (bnd.isArray()) {
3!
952
                        bnd = bnd.getElementType();
×
953
                }
954

955
                if (bnd.isPrimitive()) {
3✔
956
                        return this.ensureFamixPrimitiveType(bnd, name);
5✔
957
                }
958

959
                if (bnd.isEnum()) {
3!
960
                        return this.ensureFamixEnum(bnd, name, (ContainerEntity) owner);
×
961
                }
962

963
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
964
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
965
                }
966
                
967
                if (bnd.isAnnotation()) {
3!
968
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
×
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

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

1005
        public TType ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1006
                int modifiers = extractModifierOfTypeFrom(bnd);
4✔
1007
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1008
        }
1009
        
1010
        public TType ensureFamixType(ITypeBinding bnd) {
1011
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1012
        }
1013

1014
        private int extractModifierOfTypeFrom(ITypeBinding bnd) {
1015
                int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
1016
                return modifiers;
2✔
1017
        }
1018

1019
        public boolean isThrowable(ITypeBinding bnd) {
1020
                if (bnd == null) {
2!
1021
                        return false;
×
1022
                }
1023
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5✔
1024
                        return true;
2✔
1025
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5✔
1026
                        return false;
2✔
1027
                }
1028
                else {
1029
                        return isThrowable(bnd.getSuperclass());
5✔
1030
                }
1031
        }
1032

1033
        /**
1034
         * Returns a Famix Class associated with the ITypeBinding.
1035
         * The Entity is created if it does not exist.
1036
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
1037
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1038
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1039
         */
1040
        @SuppressWarnings("deprecation")
1041
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1042
                Class fmx = null;
2✔
1043

1044
                // --------------- some special cases
1045
                if (bnd != null) {
2✔
1046
                        if (bnd.isArray()) {
3!
1047
                                bnd = bnd.getElementType();
×
1048
                        }
1049

1050
                        // for inner classes defined in generics !!! For others should not change anything
1051
                        bnd = bnd.getErasure();
3✔
1052
                }
1053

1054
                // ---------------- to avoid useless computations if we can
1055
                fmx = (Class) getEntityByKey(bnd);
5✔
1056
                if (fmx != null) {
2✔
1057
                        return fmx;
2✔
1058
                }
1059

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

1083
                if (name.equals(OBJECT_NAME)) { // TODO && owner == java.lang
4✔
1084
                        return ensureFamixClassObject(bnd);
4✔
1085
                }
1086

1087
                // --------------- owner
1088
                if (owner == null) {
2✔
1089
                        if (bnd != null) {
2✔
1090
                                owner = ensureOwner(bnd);
4✔
1091
                        }
1092
                        /*                                owner = ensureFamixPackageDefault();
1093
                        } else {*/
1094
                }
1095

1096
                // --------------- recover from name ?
1097
                if (owner != null) {
2✔
1098
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13✔
1099
                                if (matchAndMapClass(bnd, name, (ContainerEntity) owner, candidate)) {
8✔
1100
                                        fmx = candidate;
2✔
1101
                                        break;
1✔
1102
                                }
1103
                        }
1✔
1104
                }
1105

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

1117
                if (fmx!=null) {
2!
1118
                        // we just created it or it was not bound, so we make sure it has the right information in it
1119
                        if (bnd != null) {
2✔
1120
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1121
                        }
1122
                        TAssociation lastAssoc = null;
2✔
1123

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

1136
                return fmx;
2✔
1137
        }
1138

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

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

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

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

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

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

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

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

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

1227
                return fmx;
2✔
1228
        }
1229

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

1239
                // --------------- some special cases
1240
                if (bnd != null) {
2!
1241
                        if (bnd.isArray()) {
3!
1242
                                bnd = bnd.getElementType();
×
1243
                        }
1244

1245
                        // for inner classes defined in generics !!! For others should not change anything
1246
                        bnd = bnd.getErasure();
3✔
1247
                }
1248

1249
                // ---------------- to avoid useless computations if we can
1250
                fmx = (Interface) getEntityByKey(bnd);
5✔
1251
                if (fmx != null) {
2✔
1252
                        return fmx;
2✔
1253
                }
1254

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

1278
                // --------------- owner
1279
                if (owner == null) {
2✔
1280
                        if (bnd == null) {
2!
1281
                                owner = ensureFamixPackageDefault();
×
1282
                        } else {
1283
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1284
                        }
1285
                }
1286

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

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

1306
                if (fmx!=null) {
2!
1307
                        // we just created it or it was not bound, so we make sure it has the right information in it
1308
                        if (bnd != null) {
2!
1309
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5✔
1310
                        }
1311
                        TAssociation lastAssociation = null;
2✔
1312
                        if (bnd != null) {
2!
1313
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6✔
1314
                        }
1315
                }
1316
                return fmx;
2✔
1317
        }
1318

1319
        public TType asClass(TType excepFmx) {
1320
                Class tmp = null;
×
1321
                IBinding key = null;
×
1322
                try {
1323
                        TWithTypes owner = (TWithTypes) Util.getOwner(excepFmx);
×
1324
                        owner.getTypes().remove(excepFmx);
×
1325
                        removeEntity((NamedEntity) excepFmx);
×
1326

1327
                        key = entityToKey.get((NamedEntity) excepFmx);
×
1328
                        tmp = ensureFamixEntity(Class.class, key, excepFmx.getName());
×
1329
                        tmp.setTypeContainer((ContainerEntity)owner);
×
1330

1331
                        tmp.addMethods(((TWithMethods) excepFmx).getMethods());
×
1332
                        if (excepFmx instanceof TWithAttributes) {
×
1333
                                tmp.addAttributes(((TWithAttributes) excepFmx).getAttributes());
×
1334
                        }
1335

1336
                        if (key != null) {
×
1337
                                setClassModifiers(tmp, key.getModifiers());
×
1338
                        }
1339

1340
                        if (excepFmx instanceof TWithInheritances) {
×
1341
                                tmp.addSuperInheritances(((TWithInheritances) excepFmx).getSuperInheritances());
×
1342
                                tmp.addSubInheritances(((TWithInheritances) excepFmx).getSubInheritances());
×
1343
                        }
1344
                        tmp.setSourceAnchor(excepFmx.getSourceAnchor());
×
1345
                        tmp.addAnnotationInstances(((NamedEntity) excepFmx).getAnnotationInstances());
×
1346
                        // tmp.addComments(excepFmx.getComments());
1347
                        tmp.addIncomingReferences(excepFmx.getIncomingReferences());
×
1348
                        tmp.setIsStub(excepFmx.getIsStub());
×
1349
                        tmp.addTypes(((ContainerEntity) excepFmx).getTypes());
×
1350
                }
1351
                catch( ConcurrentModificationException e) {
×
1352
                        e.printStackTrace();
×
1353
                }
×
1354

1355
                return tmp;
×
1356
        }
1357

1358
        public TThrowable asException(TType excepFmx) {
1359
                if (excepFmx instanceof Exception) {
3✔
1360
                        return (Exception) excepFmx;
3✔
1361
                }
1362
                if(excepFmx instanceof TypeParameter) {
3✔
1363
                        return (TypeParameter) excepFmx;
3✔
1364
                }
1365
                Exception tmp = null;
2✔
1366
                IBinding key = null;
2✔
1367
                try {
1368
                        TWithTypes owner = (TWithTypes) Util.getOwner(excepFmx);
4✔
1369
                        owner.getTypes().remove(excepFmx);
5✔
1370
                        removeEntity((NamedEntity) excepFmx);
4✔
1371

1372
                        key = entityToKey.get((NamedEntity) excepFmx);
7✔
1373
                        tmp = ensureFamixException((ITypeBinding) key, excepFmx.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1374

1375
                        tmp.addMethods(((TWithMethods) excepFmx).getMethods());
5✔
1376
                        if (excepFmx instanceof TWithAttributes) {
3!
1377
                                tmp.addAttributes(((TWithAttributes) excepFmx).getAttributes());
5✔
1378
                        }
1379

1380
                        if (excepFmx instanceof TWithInheritances) {
3!
1381
                                tmp.addSuperInheritances(((TWithInheritances) excepFmx).getSuperInheritances());
5✔
1382
                                tmp.addSubInheritances(((TWithInheritances) excepFmx).getSubInheritances());
5✔
1383
                        }
1384
                        tmp.setSourceAnchor(excepFmx.getSourceAnchor());
4✔
1385
                        tmp.addAnnotationInstances(((NamedEntity) excepFmx).getAnnotationInstances());
5✔
1386
                        // tmp.addComments(excepFmx.getComments());
1387
                        List<TReference> newList = excepFmx.getIncomingReferences().stream().collect(Collectors.toList());
7✔
1388
                        tmp.addIncomingReferences(newList);
3✔
1389
                        tmp.setIsStub(excepFmx.getIsStub());
4✔
1390
                        tmp.addTypes(((ContainerEntity) excepFmx).getTypes());
5✔
1391
                }
1392
                catch( ConcurrentModificationException e) {
×
1393
                        e.printStackTrace();
×
1394
                }
1✔
1395

1396
                return (TThrowable)tmp;
2✔
1397
        }
1398

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

1406
        /**
1407
         * helper method, we know the type exists, ensureFamixInterface will recover it
1408
         */
1409
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1410
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1411
        }
1412

1413
        /**
1414
         * helper method, we know the type exists, ensureFamixInterface will recover it
1415
         */
1416
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1417
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1418
        }
1419

1420
        /**
1421
         * Ensures a famix entity for the owner of a binding.<br>
1422
         * This owner can be a method, a class or a namespace
1423
         * @param bnd -- binding for the owned entity
1424
         * @return a famix entity for the owner
1425
         */
1426
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1427
                TNamedEntity owner = null;
2✔
1428
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3✔
1429
                if (parentMtd != null) {
2✔
1430
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5✔
1431
                }
1432
                else {
1433
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3✔
1434
                        if (parentClass != null) {
2✔
1435
                                TType tmpOwn = this.ensureFamixType(parentClass);
4✔
1436
                                if (tmpOwn instanceof ParametricClass) {
3✔
1437
                                        owner =  (TNamedEntity) ((ParametricClass) tmpOwn);
4✔
1438
                                }
1439
                                else {
1440
                                        owner = tmpOwn;
2✔
1441
                                }
1442
                        }
1✔
1443
                        else {
1444
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1445
                                if (parentPckg != null) {
2!
1446
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1447
                                } else {
1448
                                        owner = this.ensureFamixPackageDefault();
×
1449
                                }
1450
                        }
1451
                }
1452
                return owner;
2✔
1453
        }
1454

1455

1456
        /**
1457
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1458
         * We assume that PrimitiveType must be uniq for a given name
1459
         * @param name -- the name of the FAMIX PrimitiveType
1460
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1461
         */
1462
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1463
                if (name == null) {
2✔
1464
                        if (bnd == null) {
2!
1465
                                return null;
×
1466
                        } else {
1467
                                name = bnd.getName();
3✔
1468
                        }
1469
                }
1470
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7✔
1471
        }
1472

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

1476
                // --------------- to avoid useless computations if we can
1477
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1478
                if (fmx != null) {
2✔
1479
                        return fmx;
2✔
1480
                }
1481

1482
                // --------------- name
1483
                if (name == null) {
2✔
1484
                        if (bnd == null) {
2!
1485
                                return null;
×
1486
                        }
1487
                        else {
1488
                                name = bnd.getName();
3✔
1489
                        }
1490
                }
1491

1492
                // --------------- owner
1493
                if (owner == null) {
2✔
1494
                        if (bnd == null) {
2!
1495
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1496
                        } else {
1497
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1498
                        }
1499
                }
1500

1501
                // --------------- recover from name ?
1502
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1503
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1504
                                fmx = candidate;
×
1505
                                break;
×
1506
                        }
1507
                }
×
1508

1509
                if (fmx == null) {
2!
1510
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1511
                        fmx.setTypeContainer(owner);
3✔
1512
                }
1513

1514
                if ((fmx != null) && (bnd != null) ) {
4!
1515
                        setVisibility(fmx, bnd.getModifiers());
5✔
1516
                }
1517

1518
                return fmx;
2✔
1519
        }
1520

1521
        /**
1522
         * helper method, we know the type exists, ensureFamixEnum will recover it
1523
         */
1524
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1525
                return ensureFamixEnum(bnd, name, owner);
6✔
1526
        }
1527

1528
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1529
                EnumValue fmx = null;
2✔
1530

1531
                // --------------- to avoid useless computations if we can
1532
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1533
                if (fmx != null) {
2✔
1534
                        return fmx;
2✔
1535
                }
1536

1537
                // --------------- name
1538
                if (name == null) {
2!
1539
                        if (bnd == null) {
×
1540
                                return null;
×
1541
                        }
1542
                        else {
1543
                                name = bnd.getName();
×
1544
                        }
1545
                }
1546

1547
                // --------------- owner
1548
                if (owner == null) {
2✔
1549
                        if (bnd == null) {
2!
1550
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1551
                        }
1552
                        else {
1553
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1554
                        }
1555
                }
1556

1557
                // --------------- recover from name ?
1558
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
1559
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1560
                                fmx = candidate;
×
1561
                                break;
×
1562
                        }
1563
                }
×
1564
                if (fmx == null) {
2!
1565
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1566
                        fmx.setParentEnum(owner);
3✔
1567
                }
1568

1569
                if (fmx!=null) {
2!
1570
                        fmx.setParentEnum(owner);
3✔
1571
                }
1572

1573
                return fmx;
2✔
1574
        }
1575

1576
        /**
1577
         * helper method, we know the type enumValue, ensureFamixEnumValue will recover it
1578
         */
1579
        public EnumValue getFamixEnumValue(IVariableBinding bnd, String name, Enum owner) {
1580
                return ensureFamixEnumValue(bnd, name, owner);
×
1581
        }
1582

1583
        /**
1584
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1585
         */
1586
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1587
                AnnotationType fmx = null;
2✔
1588

1589
                // --------------- to avoid useless computations if we can
1590
                fmx = (AnnotationType)getEntityByKey(bnd);
5✔
1591
                if (fmx != null) {
2✔
1592
                        return fmx;
2✔
1593
                }
1594

1595
                // --------------- name
1596
                if (name == null) {
2✔
1597
                        if (bnd == null) {
2!
1598
                                return null;
×
1599
                        }
1600
                        else {
1601
                                name = bnd.getName();
3✔
1602
                        }
1603
                }
1604

1605
                // --------------- owner
1606
                if (owner == null) {
2✔
1607
                        if (bnd == null) {
2!
1608
                                owner = ensureFamixPackageDefault();
×
1609
                        }
1610
                        else {
1611
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1612
                                if (parentPckg != null) {
2!
1613
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1614
                                } else {
1615
                                        owner = this.ensureFamixPackageDefault();
×
1616
                                }
1617
                        }
1618
                }
1619

1620
                // --------------- recover from name ?
1621
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1622
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1623
                                fmx = candidate;
2✔
1624
                                break;
1✔
1625
                        }
1626
                }
1✔
1627

1628
                // --------------- create
1629
                if (fmx == null) {
2✔
1630
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1631
                        fmx.setAnnotationTypesContainer(owner);
3✔
1632
                }
1633

1634
                if ( (fmx!=null) && (bnd != null) ) {
4!
1635
                        // Not supported in Famix
1636

1637
                        // setVisibility(fmx, bnd.getModifiers());
1638
                }
1639

1640
                return fmx;
2✔
1641
        }
1642

1643
        /**
1644
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1645
         */
1646
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1647
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1648
        }
1649

1650
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1651
                AnnotationTypeAttribute fmx = null;
2✔
1652

1653
                // --------------- to avoid useless computations if we can
1654
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5✔
1655
                if (fmx != null) {
2✔
1656
                        return fmx;
2✔
1657
                }
1658

1659
                // --------------- name
1660
                if (name == null) {
2!
1661
                        if (bnd == null) {
×
1662
                                return null;
×
1663
                        }
1664
                        else {
1665
                                name = bnd.getName();
×
1666
                        }
1667
                }
1668

1669
                // --------------- owner
1670
                if (owner == null) {
2!
1671
                        if (bnd == null) {
×
1672
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1673
                        }
1674
                        else {
1675
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1676
                                if (parentType != null) {
×
1677
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1678
                                }
1679
                                else  {
1680
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1681
                                }
1682
                        }
1683
                }
1684

1685
                // --------------- recover from name ?
1686
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13✔
1687
                        // JDT treats annotation type attributes as methods ...
1688
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1689
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11!
1690
                                fmx = candidate;
×
1691
                                break;
×
1692
                        }
1693
                        // if the binding is null, the annotationTypeAttribute migth have been created
1694
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2!
1695
                                fmx = candidate;
×
1696
                                break;
×
1697
                        }
1698
                }
1✔
1699

1700
                if (fmx == null) {
2!
1701
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1702
                        fmx.setParentType(owner);
3✔
1703
                }
1704

1705
                if ( (fmx!=null) && (bnd != null) ) {
4!
1706
                        // Not suopp
1707

1708
                        // setVisibility(fmx, bnd.getModifiers());
1709
                }
1710

1711
                return fmx;
2✔
1712
        }
1713

1714
        /**
1715
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1716
         */
1717
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1718
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6✔
1719
        }
1720
        
1721
        
1722
        /**
1723
         * Returns a FAMIX Wildcard with its bounds
1724
         * @param bnd
1725
         * @param name
1726
         * @param owner
1727
         * @return
1728
         */
1729
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1730
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8✔
1731
                if(bnd.getBound() != null) {
3✔
1732
                        Type bound = (Type) this.ensureFamixType(bnd.getBound()); 
6✔
1733
                        if(bnd.isUpperbound()) {
3✔
1734
                                fmx.setUpperBound(bound);
3✔
1735
                                bound.addUpperBoundedWildcards(fmx);
4✔
1736
                        }else{
1737
                                fmx.setLowerBound(bound);
3✔
1738
                                bound.addLowerBoundedWildcards(fmx);
3✔
1739
                        }
1740
                }
1741
                return fmx;
2✔
1742
        }
1743

1744
        /**
1745
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1746
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1747
         * @param name -- the name of the Famix TypeParameter
1748
         * @return the Famix TypeParameter or null in case of a Famix error
1749
         */
1750
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1751
                TypeParameter fmx = null;
2✔
1752

1753
                // --------------- to avoid useless computations if we can
1754
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1755
                if (fmx != null) {
2✔
1756
                        return fmx;
2✔
1757
                }
1758

1759
                // --------------- name
1760
                if (name == null) {
2✔
1761
                        if (bnd == null) {
2!
1762
                                return null;
×
1763
                        }
1764
                        else {
1765
                                name = bnd.getName();
3✔
1766
                        }
1767
                }
1768

1769
                // --------------- owner
1770
                if (owner == null) {
2!
UNCOV
1771
                        if (bnd == null) {
×
1772
                                owner = null;  // not really sure what to do here
×
1773
                        }
1774
                        else {
UNCOV
1775
                                if (bnd.getDeclaringClass() != null) {
×
NEW
1776
                                        owner = (TWithTypes) this.ensureFamixType(bnd.getDeclaringClass());
×
UNCOV
1777
                                }else if(bnd.getDeclaringMethod() != null) {
×
NEW
1778
                                        owner = (TWithTypes) this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1779
                                }
1780
                                else {
1781
                                        owner = null;  // not really sure what to do here
×
1782
                                }
1783
                        }
1784
                }
1785

1786
                // --------------- recover from name ?
1787
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1788
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1789
                                fmx = (TypeParameter) candidate;
3✔
1790
                                break;
1✔
1791
                        }
1792
                }
1✔
1793

1794
                // --------------- create
1795
                if (fmx == null) {
2✔
1796
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1797
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1798
                                Type upperBound = (Type)ensureFamixType(bnd.getSuperclass());
6✔
1799
                                fmx.setUpperBound(upperBound);
3✔
1800
                        }
1801
                        if(bnd != null && bnd.getInterfaces().length > 0) {
6✔
1802
                                for(ITypeBinding intbnd: bnd.getInterfaces()) {
17✔
1803
                                        Type upperBound = (Type)ensureFamixType(intbnd);
5✔
1804
                                        fmx.setUpperBound(upperBound);
3✔
1805
                                }
1806
                        }
1807
                        fmx.setTypeContainer((ContainerEntity) owner);
4✔
1808
                }
1809

1810
                return fmx;
2✔
1811
        }
1812

1813

1814
        public IBinding getTypeParameterOwner(ITypeBinding typeParameterBinding, IBinding currentOwner) {
1815
                
1816

1817

NEW
1818
                return currentOwner;
×
1819
        }
1820

1821

1822

1823
        /**
1824
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1825
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1826
         *
1827
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1828
         * @param name      of the package
1829
         * @param owner     of the package
1830
         * @param candidate -- a Famix Entity
1831
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1832
         */
1833
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1834
                if (!(candidate instanceof Package)) {
3!
1835
                        return false;
×
1836
                }
1837

1838
                // check whether bnd and candidate are already bound
1839
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1840
                if (res == CheckResult.MATCH) {
3✔
1841
                        return true;
2✔
1842
                } else if (res == CheckResult.FAIL) {
3✔
1843
                        return false;
2✔
1844
                }
1845

1846
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1847
                        return false;
2✔
1848
                }
1849

1850
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1851
                conditionalMapToKey(bnd, candidate);
4✔
1852
                return true;
2✔
1853
        }
1854

1855
        /**
1856
         * Checks whether the existing unmapped Famix Type matches the binding.
1857
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1858
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1859
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1860
         * @param name of the type
1861
         * @param owner of the type
1862
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1863
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1864
         */
1865
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1866
                if (! (candidate instanceof Type) ) {
3!
1867
                        return false;
×
1868
                }
1869

1870
                // check whether bnd and candidate are already bound
1871
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1872
                if (res == CheckResult.MATCH) {
3✔
1873
                        return true;
2✔
1874
                }
1875
                else if (res == CheckResult.FAIL) {
3✔
1876
                        return false;
2✔
1877
                }
1878

1879
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
1880
                                bnd = bnd.getElementType();
×
1881
                }
1882

1883
                // checking names
1884
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
1885
                        name = bnd.getErasure().getName();
×
1886
                }
1887
                else if (bnd != null) {
2✔
1888
                        name = bnd.getName();
3✔
1889
                }
1890
                // else name = name
1891
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1892
                        return false;
2✔
1893
                }
1894

1895
                // special case of primitive types
1896
                if (candidate instanceof PrimitiveType) {
3!
1897
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1898
                                // names are equal so it's OK
1899
                                conditionalMapToKey(bnd, candidate);
×
1900
                                return true;
×
1901
                        }
1902
                        else if ( (bnd == null) && (owner == null) ) {
×
1903
                                return true;
×
1904
                        }
1905
                }
1906

1907
                // check owners without bnd
1908
                if (bnd == null) {
2✔
1909
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1910
                }
1911

1912
                // check owners with bnd
1913
                // type is an annotation
1914
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1915
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1916
                                conditionalMapToKey(bnd, candidate);
4✔
1917
                                return true;
2✔
1918
                        } else {
1919
                                return false;
×
1920
                        }
1921
                }
1922

1923
                // check owners with bnd
1924
                // type is a Parameterized type
1925
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
1926
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1927
                }
1928

1929
                // check owners with bnd
1930
                // type is an Enum
1931
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
1932
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1933
                }
1934

1935
                // check owners with bnd
1936
                // type is something elae (a class or interface)
1937
                // Annotation are interfaces too, so we should check this one after isAnnotation
1938
                if ( bnd.isClass()) {
3!
1939
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1940
                }
1941

1942
                if(bnd.isInterface()) {
3!
1943
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1944
                }
1945

1946
                return false;
2✔
1947
        }
1948

1949
        /**
1950
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1951
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1952
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1953
         * @param name of the class
1954
         * @param owner of the class
1955
         * @param candidate -- a Famix Entity
1956
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1957
         */
1958
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1959
                if (!(candidate instanceof Class)) {
3!
1960
                        return false;
×
1961
                }
1962

1963
                // check whether bnd and candidate are already bound
1964
                CheckResult res = checkKeyMatch(bnd, (NamedEntity) candidate);
6✔
1965
                if (res == CheckResult.MATCH) {
3!
1966
                        return true;
×
1967
                } else if (res == CheckResult.FAIL) {
3✔
1968
                        return false;
2✔
1969
                }
1970

1971
                if (checkNameMatch(bnd, name, (NamedEntity) candidate) == CheckResult.FAIL) {
8!
1972
                        return false;
×
1973
                }
1974

1975
                // checking owner
1976
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1977
        }
1978

1979
        /**
1980
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1981
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1982
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1983
         * @param name of the class
1984
         * @param owner of the class
1985
         * @param candidate -- a Famix Entity
1986
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1987
         */
1988
        private boolean matchAndMapInterface(ITypeBinding bnd, String name, TNamedEntity owner, Type candidate) {
1989
                if (!(candidate instanceof Interface)) {
3!
1990
                        return false;
×
1991
                }
1992

1993
                // check whether bnd and candidate are already bound
1994
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1995
                if (res == CheckResult.MATCH) {
3!
1996
                        return true;
×
1997
                } else if (res == CheckResult.FAIL) {
3✔
1998
                        return false;
2✔
1999
                }
2000

2001
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2002
                        return false;
×
2003
                }
2004

2005
                // checking owner
2006
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
2007
        }
2008

2009
        /**
2010
         * Checks whether the existing unmapped Famix "Method" matches the binding.
2011
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
2012
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
2013
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2014
         * @param sig -- signature of the method
2015
         * @param retTyp -- return type of the method
2016
         * @param owner of the method
2017
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
2018
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2019
         */
2020
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
2021
                if (! (candidate instanceof Method) ) {
3✔
2022
                        return false;
2✔
2023
                }
2024

2025
                // check whether bnd and candidate are already bound
2026
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
2027
                if (res == CheckResult.MATCH) {
3!
UNCOV
2028
                        return true;
×
2029
                }
2030
                else if (res == CheckResult.FAIL) {
3✔
2031
                        return false;
2✔
2032
                }
2033

2034
                // checking names
2035
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
2036
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2037
                        return false;
×
2038
                }
2039

2040
                // for methods, the name is not enough, we must test the signature also
2041
                // but not for AnnotationTypeAttribute
2042

2043
                        if (bnd != null) {
2✔
2044
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
2045
                        }
2046
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
2047
                                return false;
2✔
2048
                        }
2049

2050
                        // and still for method, must also check the return type
2051
                        if (bnd != null) {
2✔
2052
                                if (bnd.isConstructor()) {
3!
2053
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
×
2054
                                                return false;
×
2055
                                        }
2056
                                        // else OK for now
2057
                                }
2058
                                else { // not a constructor
2059
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4!
2060
                                                return false;
×
2061
                                        }
2062
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10!
2063
                                                return false;
×
2064
                                        }
2065
                                        // else OK for now
2066
                                }
2067
                        }
2068
                        else {  // bnd == null
2069
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2!
2070
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4!
2071
                                                return false;
×
2072
                                        }
2073
                                        // else OK for now
2074
                                } else { // (ret != null)  i.e. not a constructor
2075
                                        if (((Method) candidate).getDeclaredType() == null) {
×
2076
                                                return false;
×
2077
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
2078
                                                return false;
×
2079
                                        }
2080
                                        // else OK for now
2081
                                }
2082
                        }
2083

2084

2085
                // check owner
2086
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2087
                        conditionalMapToKey(bnd, candidate);
4✔
2088
                        return true;
2✔
2089
                } else {
2090
                        return false;
2✔
2091
                }
2092
        }
2093

2094
        /**
2095
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2096
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2097
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2098
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2099
         * @param name of the variable
2100
         * @param owner of the variable
2101
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2102
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2103
         */
2104
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2105
                if (!(candidate instanceof TStructuralEntity)) {
3!
2106
                        return false;
×
2107
                }
2108

2109
                // check whether bnd and candidate are already bound
2110
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5✔
2111
                if (keyMatch == CheckResult.MATCH) {
3!
2112
                        return true;
×
2113
                } else if (keyMatch == CheckResult.FAIL) {
3✔
2114
                        return false;
2✔
2115
                }
2116

2117
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2118
                        return false;
×
2119
                }
2120

2121
                // check owner
2122
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2123

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

2134
                // check owner
2135
                // <anArray>.length field?
2136
                if (name.equals("length")) {
4!
2137
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2138
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2139
                        if (isArrayLengthField) {
×
2140
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2141
                                        conditionalMapToKey(bnd, candidate);
×
2142
                                        return true;
×
2143
                                }
2144
                                else {
2145
                                        return false;
×
2146
                                }
2147
                        }
2148
                }
2149

2150
                // check owner
2151
                // "normal" field?
2152
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2153
                if (res == CheckResult.MATCH) {
3!
2154
                        conditionalMapToKey(bnd, candidate);
4✔
2155
                        return true;
2✔
2156
                }
2157
                return false;
×
2158
        }
2159

2160
        /**
2161
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2162
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2163
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2164
         * @param owner -- the owner of the type
2165
         * @param candidate -- a Famix Entity
2166
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2167
         */
2168
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2169
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4✔
2170

2171
                // owner is a Method? (for example in case of an anonymous class)
2172
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2173
                if (res == CheckResult.MATCH) {
3!
2174
                        conditionalMapToKey(bnd, candidate);
×
2175
                        return true;
×
2176
                } else if (res == CheckResult.FAIL) {
3!
2177
                        return false;
×
2178
                }
2179

2180
                // owner is a class ?
2181
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2182
                if (res == CheckResult.MATCH) {
3✔
2183
                        conditionalMapToKey(bnd, candidate);
4✔
2184
                        return true;
2✔
2185
                }
2186
                else if (res == CheckResult.FAIL) {
3✔
2187
                        return false;
2✔
2188
                }
2189

2190
                // owner must be a package
2191
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2192
                        conditionalMapToKey(bnd, candidate);
4✔
2193
                        return true;
2✔
2194
                }
2195
                return false;
2✔
2196
        }
2197

2198
        /**
2199
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2200
         * @param methBnd
2201
         * @param owner
2202
         * @param candidateOwner
2203
         * @return a {@link CheckResult}
2204
         */
2205
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2206
                if ((methBnd != null) || ((owner != null) && (owner instanceof Method))) {
7!
2207
                        if (!(candidateOwner instanceof Method)) {
3!
2208
                                return CheckResult.FAIL;
×
2209
                        }
2210

2211
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2212
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2213
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2214

2215
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
2216
                                return CheckResult.MATCH;
×
2217
                        } else {
2218
                                return CheckResult.FAIL;
2✔
2219
                        }
2220
                }
2221
                return CheckResult.UNDECIDED;
2✔
2222
        }
2223

2224
        /**
2225
         * @param typBnd
2226
         * @param owner
2227
         * @param candidateOwner
2228
         * @return a {@link CheckResult}
2229
         */
2230
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2231
                if ((typBnd != null) || ((owner != null) && (owner instanceof Type))) {
7!
2232
                        if (!(candidateOwner instanceof Type)) {
3✔
2233
                                return CheckResult.FAIL;
2✔
2234
                        }
2235

2236
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2237
                        String ownerName = (owner != null) ? ((Type) owner).getName() : null;
7!
2238

2239
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2240
                                return CheckResult.MATCH;
2✔
2241
                        } else {
2242
                                return CheckResult.FAIL;
2✔
2243
                        }
2244
                }
2245
                return CheckResult.UNDECIDED;
2✔
2246
        }
2247

2248
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2249
                if ((pckgBnd != null) || ((owner != null) && (owner instanceof Package))) {
7!
2250
                        if (!(candidateOwner instanceof Package)) {
3!
2251
                                return CheckResult.FAIL;
×
2252
                        }
2253

2254
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2255
                        String ownerName = (owner != null) ? ((Package) owner).getName() : null;
7!
2256

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

2266
        /**
2267
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2268
         * 'name' and 'bnd' cannot be null together
2269
         * @param bnd -- binding associated with the entity may be null
2270
         * @param name -- name of the entity may be null
2271
         * @param candidate
2272
         * @return true if names match, false if not
2273
         */
2274
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2275
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8!
2276
                        return CheckResult.FAIL;
×
2277
                }
2278
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9!
2279
                        return CheckResult.FAIL;
2✔
2280
                }
2281
                else {
2282
                        return CheckResult.MATCH;
2✔
2283
                }
2284
        }
2285

2286
        /**
2287
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2288
         * @param key
2289
         * @param candidate
2290
         * @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>
2291
         */
2292
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2293
                if (key == null) {
2✔
2294
                        return CheckResult.UNDECIDED;
2✔
2295
                }
2296

2297
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2298
                if (bound == candidate) {
3✔
2299
                        return CheckResult.MATCH;
2✔
2300
                }
2301
                else if (bound != null) {
2✔
2302
                        return CheckResult.FAIL;
2✔
2303
                }
2304
                else if (getEntityKey(candidate) != null) {
4✔
2305
                        // candidate already bound, and not to this binding
2306
                        return CheckResult.FAIL;
2✔
2307
                }
2308
                else {
2309
                        return CheckResult.UNDECIDED;
2✔
2310
                }
2311
        }
2312

2313
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2314
                if (bnd != null) {
2✔
2315
                        mapEntityToKey(bnd, ent);
4✔
2316
                }
2317
        }
1✔
2318

2319
        public Method ensureFamixMethod(IMethodBinding bnd) {
2320
                return ensureFamixMethod(
9✔
2321
                                bnd,
2322
                                /*name*/null,
2323
                                /*paramsType*/(Collection<String>)null,
2324
                                /*returnType*/null,
2325
                                /*owner*/null,
2326
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2327
        }
2328

2329
        /**
2330
         * Returns a Famix Method associated with the IMethodBinding. The Entity is created if it does not exist.
2331
         * The Entity is created if it does not exist.
2332
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
2333
         * @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)
2334
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2335
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2336
         */
2337
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2338
                Method fmx = null;
2✔
2339
                String sig;
2340
                boolean delayedRetTyp;
2341

2342
                // --------------- to avoid useless computations if we can
2343
                fmx = (Method)getEntityByKey(bnd);
5✔
2344
                if (fmx != null) {
2✔
2345
                        return fmx;
2✔
2346
                }
2347

2348
                // --------------- name
2349
                if (name == null) {
2✔
2350
                        if (bnd == null) {
2✔
2351
                                return null;
2✔
2352
                        }
2353
                        else {
2354
                                name = bnd.getName();
3✔
2355
                        }
2356
                }
2357

2358
                // --------------- signature
2359
                sig = name + "(";
3✔
2360
                 if (bnd != null) {
2✔
2361
                    sig += signatureParamsFromBinding(bnd);
7✔
2362
                }
2363
        else if (paramTypes != null) {
2!
2364
                        sig += signatureParamsFromStringCollection(paramTypes);
7✔
2365
                }
2366
                else {
2367
                        sig += "???";
×
2368
                }
2369
                sig += ")";
3✔
2370

2371
                // --------------- return type
2372
                delayedRetTyp = false;
2✔
2373
                ITypeBinding retTypBnd = null;
2✔
2374
                if (ret == null) {
2!
2375
                        if (bnd == null) {
2✔
2376
                                ret = null;  // what else ?
3✔
2377
                        }
2378
                        else {
2379
                                if (bnd.isConstructor()) {
3✔
2380
                                        ret = null;
3✔
2381
                                }
2382
                                else {
2383

2384
                                        // must create the return type
2385
                                        // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2386
                                        // we need T to create the method and the method to create T ...
2387
                                        // so we need to test the situation and deal with it
2388
                                        retTypBnd = bnd.getReturnType();
3✔
2389
                                        if (retTypBnd == null) {
2✔
2390
                                                ret = null;
3✔
2391
                                        }
2392
                                        else if (retTypBnd.isArray()) {
3✔
2393
                                                retTypBnd = retTypBnd.getElementType();
3✔
2394
                                        }
2395

2396
                                        if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2397
                                                ret = null;
2✔
2398
                                                delayedRetTyp = true;
3✔
2399
                                        }
2400
                                        else {
2401
                                                ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2402
                                        }
2403
                                }
2404
                        }
2405
                }
2406

2407
                // --------------- owner
2408
                if (owner == null) {
2✔
2409
                        if (bnd == null) {
2✔
2410
                                owner = ensureFamixClassStubOwner();
4✔
2411
                        }
2412
                        else {
2413
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2414
                                if (classBnd != null) {
2!
2415
                                        TType tmpOwn = ensureFamixType(classBnd);
4✔
2416

2417
                                        owner = (TWithMethods) tmpOwn;
3✔
2418
                                        
2419
                                }
1✔
2420
                                else {
2421
                                        owner = ensureFamixClassStubOwner();
×
2422
                                }
2423
                        }
2424
                }
2425

2426
                // --------------- recover from name ?
2427
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2428
                        if (matchAndMapMethod(bnd, sig, ret, (TNamedEntity) owner, candidate)) {
9✔
2429
                                fmx = candidate;
2✔
2430
                                break;
1✔
2431
                        }
2432
                }
1✔
2433

2434
                if (fmx == null) {
2✔
2435
                        if(bnd != null && bnd.isGenericMethod()) {
5✔
2436
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7✔
2437
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18✔
2438
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, (TWithTypes)fmx);
6✔
2439
                                        fmxParam.addGenericEntities((ParametricMethod)fmx);
4✔
2440
                                }
2441
                        // parameterized method binding = when the method is the target of an invocation.
2442
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5!
NEW
2443
                                fmx = (ParametricMethod)this.ensureFamixMethod(bnd.getMethodDeclaration());
×
2444
                        }else{
2445
                                fmx = ensureFamixEntity(Method.class, bnd, name);
7✔
2446
                        }
2447
                        
2448
                        fmx.setSignature(sig);
3✔
2449
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7✔
2450
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6✔
2451
                        fmx.setParentType(owner);
3✔
2452
                }
2453

2454
                if (fmx != null) {
2!
2455
                        setMethodModifiers(fmx, modifiers);
4✔
2456
                        // if it's a constructor
2457
                        if (fmx.getName().equals(Util.getOwner(fmx).getName())) {
7✔
2458
                                fmx.setKind(CONSTRUCTOR_KIND_MARKER);
3✔
2459
                        }
2460
                }
2461

2462
                if ((fmx != null) && delayedRetTyp) {
4!
2463
                        int retTypModifiers = (retTypBnd != null) ? retTypBnd.getModifiers() : UNKNOWN_MODIFIERS;
6!
2464
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
5!
2465
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2466
                }
2467

2468
                return fmx;
2✔
2469
        }
2470

2471
        /**
2472
         * Creates or recovers a stub Famix Method
2473
         * @param name of the method
2474
         * @return the Famix Method
2475
         */
2476
        public Method ensureFamixStubMethod(String name) {
2477
                return ensureFamixMethod(null, name, /*paramType*/(Collection<String>)null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);  // cast needed to desambiguate the call
×
2478
        }
2479

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

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

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

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

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

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

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

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

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

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

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

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

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

2590
                return fmx;
2✔
2591
        }
2592

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

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

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

2612
                // --------------- to avoid useless computations if we can
2613
                try {
2614
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2615

2616
                }catch(Throwable e) {
×
2617
                        e.printStackTrace();
×
2618
                }
1✔
2619
                if (fmx != null) {
2✔
2620
                        return fmx;
2✔
2621
                }
2622

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

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

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

2651
                if (fmx == null) {
2!
2652
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2653
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2654
                }
2655

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

2662
                return fmx;
2✔
2663
        }
2664

2665
        /**
2666
         * helper method, we know the var exists, ensureFamixParameter will recover it
2667
         */
2668
        public Parameter getFamixParameter(IVariableBinding bnd, String name, TMethod tMethod) {
2669
                return ensureFamixParameter(bnd, name, /*declared type*/null, tMethod);
×
2670
        }
2671

2672
        /**
2673
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2674
         * The Entity is created if it does not exist.<br>
2675
         * @param name -- the name of the FAMIX LocalVariable
2676
         * @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
2677
         */
2678
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2679
                LocalVariable fmx = null;
2✔
2680

2681
                // --------------- to avoid useless computations if we can
2682
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2683
                if (fmx != null) {
2!
2684
                        return fmx;
×
2685
                }
2686

2687
                // --------------- name
2688
                if (name == null) {
2!
2689
                        if (bnd == null) {
×
2690
                                return null;
×
2691
                        }
2692
                        else {
2693
                                name = bnd.getName();
×
2694
                        }
2695
                }
2696

2697
                // --------------- owner
2698
                if (owner == null) {
2!
2699
                        if (bnd == null) {
×
2700
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2701
                        }
2702
                        else {
2703
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2704
                        }
2705
                }
2706

2707
                // --------------- recover from name ?
2708
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2709
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
2710
                                fmx = candidate;
×
2711
                                break;
×
2712
                        }
2713
                }
1✔
2714

2715
                if (fmx == null) {
2!
2716
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2717
                        fmx.setParentBehaviouralEntity(owner);
3✔
2718
                }
2719

2720
                if (fmx != null) {
2!
2721
                        // we just created it or it was not bound, so we make sure it has the right information in it
2722
                        fmx.setParentBehaviouralEntity(owner);
3✔
2723
                }
2724

2725
                return fmx;
2✔
2726
        }
2727

2728
        /**
2729
         * helper method, we know the var exists, ensureFamixLocalVariable will recover it
2730
         */
2731
        public LocalVariable getFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2732
                return ensureFamixLocalVariable(bnd, name, owner);
×
2733
        }
2734

2735
        /**
2736
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2737
         * If this ImplicitVariable does not exist yet, it is created
2738
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2739
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2740
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2741
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2742
         */
2743
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2744
                ImplicitVariable fmx;
2745
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7✔
2746
                fmx.setParentBehaviouralEntity(tMethod);
3✔
2747
                return fmx;
2✔
2748
        }
2749

2750
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2751
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2752
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2753
        }
2754

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

2764
                if ( (jCmt != null) && (owner != null) ) {
4!
2765
                        
2766
                        cmt = new Comment();
4✔
2767
                        addSourceAnchor(cmt, jCmt);
5✔
2768
                        famixRepoAdd(cmt);
3✔
2769
                        cmt.setCommentedEntity(owner);
3✔
2770
                }
2771

2772
                return cmt;
2✔
2773
        }
2774

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

2785
                if ( (jCmt != null) && (owner != null) ) {
4!
2786
                        cmt = new Comment();
4✔
2787
                        cmt.setContent(content );
3✔
2788
                        famixRepoAdd(cmt);
3✔
2789
                        cmt.setCommentedEntity(owner);
3✔
2790
                }
2791

2792
                return cmt;
2✔
2793
        }
2794

2795
        /**
2796
         * Adds location information to a Famix Entity.
2797
         * 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.
2798
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2799
         * @param fmx -- Famix Entity to add the anchor to
2800
         * @param node -- JDT ASTNode, where the information is extracted
2801
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2802
         */
2803
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2804
                IndexedFileAnchor fa = null;
2✔
2805

2806
                fa = createIndexedFileAnchor(node);
4✔
2807
                if ((fmx != null) && (fa != null)) {
4!
2808
                        fmx.setSourceAnchor(fa);
3✔
2809
                        famixRepoAdd(fa);
3✔
2810
                }
2811

2812
                return fa;
2✔
2813
        }
2814

2815
        /**
2816
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2817
         */
2818
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2819
                IndexedFileAnchor fa = null;
2✔
2820

2821
                fa = createIndexedFileAnchor(node);
4✔
2822
                if ((fmx != null) && (fa != null)) {
4!
2823

2824
                        // may change the positions
2825
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2826
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2827
                        if (node.getName() != null) {
3!
2828
                                methodDeclarationModifiers.add(node.getName());
5✔
2829
                        }
2830
                        if (node.getReturnType2() != null) {
3✔
2831
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2832
                        }
2833
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2834
                        int end = node.getStartPosition() + node.getLength();
6✔
2835

2836
                        ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2837
                        ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2838

2839
                        fmx.setSourceAnchor(fa);
3✔
2840
                        famixRepoAdd(fa);
3✔
2841
                }
2842

2843
                return fa;
2✔
2844
        }
2845

2846
        /**
2847
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2848
         * Information returned in the form of an IndexedFileAnchor
2849
         */
2850
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2851
                IndexedFileAnchor fa;
2852
                
2853
                if (node == null) {
2!
2854
                        return null;
×
2855
                }
2856

2857
                // position in source file
2858
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2859
                int end = beg + node.getLength() - 1;
7✔
2860

2861
                // find source Compilation Unit
2862
                // there is a special case for the JDT Comment Nodes
2863
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2864
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2865
                } else {
2866
                        node = node.getRoot();
3✔
2867
                }
2868

2869
                fa = new IndexedFileAnchor();
4✔
2870
                ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2871
                ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2872

2873
                fa.setFileName((String) ((CompilationUnit)node).getProperty(SOURCE_FILENAME_PROPERTY));
7✔
2874

2875
                return fa;
2✔
2876
        }
2877

2878
        /**
2879
         * Creates or recovers the Famix Class for "Object".
2880
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2881
         *
2882
         * @param bnd -- a potential binding for the java "Object" class
2883
         * @return a Famix class for "Object"
2884
         */
2885
        public Class ensureFamixClassObject(ITypeBinding bnd) {
2886
                Class fmx = ensureFamixUniqEntity(Class.class, bnd, OBJECT_NAME);
7✔
2887

2888
                if (fmx != null) {
2!
2889
                        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2890
                }
2891
                // Note: "Object" has no superclass
2892

2893
                return fmx;
2✔
2894
        }
2895

2896
        /**
2897
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2898
         */
2899
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2900
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2901
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2902

2903
                if (fmx != null) {
2!
2904
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2905
                }
2906

2907
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
NEW
2908
                        ensureFamixInheritance(ensureFamixClassObject(null), fmx, null, null);
×
2909
                }
2910

2911
                return fmx;
2✔
2912
        }
2913

2914
        public Class getFamixMetaClass(ITypeBinding bnd) {
2915
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2916
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2917
        }
2918

2919
        /**
2920
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
2921
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
2922
         * JDT does not create a binding for these classes, so we create a stub one here.
2923
         *
2924
         * @return a Famix class
2925
         */
2926
        public Class ensureFamixClassArray() {
2927
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
2928
                if (fmx != null) {
×
NEW
2929
                        ensureFamixInheritance(ensureFamixClassObject(null), fmx, /*prev*/null, null);
×
2930
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
2931

2932
                        // may be not needed anymore now that we use modifiers
2933
                        /*fmx.setIsAbstract(Boolean.FALSE);
2934
                        fmx.setIsFinal(Boolean.FALSE);
2935
                        fmx.setIsInterface(Boolean.FALSE); 
2936
                        fmx.setIsPrivate(Boolean.FALSE);
2937
                        fmx.setIsProtected(Boolean.FALSE);*/
2938
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2939
                }
2940

2941
                return fmx;
×
2942
        }
2943

2944
        public String removeLastPartOfPackageName(String qualifiedName) {
2945
                String ret = null;
2✔
2946
                int last = qualifiedName.lastIndexOf('.');
4✔
2947
                if (last > 0) {
2✔
2948
                        // recursively creating the parent
2949
                        ret = qualifiedName.substring(0, last);
6✔
2950
                }
2951
                else {
2952
                        ret = "";
2✔
2953
                }
2954

2955
                return ret;
2✔
2956
        }
2957

2958
        /** Generates the list of parameters for a method signature
2959
         * @return a string
2960
         */
2961
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2962
                boolean first = true;
2✔
2963
                String sig = new String();
4✔
2964

2965
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2966
                        if (first) {
2✔
2967
                                sig = parBnd.getName();
3✔
2968
                                first = false;
3✔
2969
                        }
2970
                        else {
2971
                                sig += "," + parBnd.getName();
5✔
2972
                        }
2973
                }
2974
                return sig;
2✔
2975
        }
2976

2977
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2978
                boolean first = true;
2✔
2979
                String sig = new String();
4✔
2980

2981
                for (String t : paramTypes) {
10✔
2982
                        if (first) {
2✔
2983
                                sig = t;
2✔
2984
                                first = false;
3✔
2985
                        }
2986
                        else {
2987
                                sig += "," + t;
4✔
2988
                        }
2989
                }
1✔
2990
                return sig;
2✔
2991
        }
2992

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