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

moosetechnology / VerveineJ / 20030831789

08 Dec 2025 02:05PM UTC coverage: 50.923% (-0.07%) from 50.991%
20030831789

Pull #178

github

web-flow
Merge 6433323b6 into ccd766c89
Pull Request #178: Some cleanings

1898 of 3934 branches covered (48.25%)

Branch coverage included in aggregate %.

90 of 105 new or added lines in 7 files covered. (85.71%)

2 existing lines in 2 files now uncovered.

4255 of 8149 relevant lines covered (52.21%)

2.11 hits per line

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

74.94
/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

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

57
import ch.akuhn.fame.Repository;
58
import fr.inria.verveine.extractor.java.utils.ImplicitVarBinding;
59
import fr.inria.verveine.extractor.java.utils.Util;
60

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

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

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

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

93
    /**
94
     * An MSE marker for methods
95
     */
96
    public static final String CONSTRUCTOR_KIND_MARKER = "constructor";
97

98
    /**
99
     * The symbol kind to use to define that a method is a default implementation in an interface
100
     */
101
    public static final String DEFAULT_IMPLEMENTATION_KIND_MARKER = "default";
102

103
        /** name of the entity representing the "unknown" type 'var'
104
         * The entity is intended to be uniq, see {@link #ensureFamixUniqEntity(java.lang.Class, IBinding , String )}
105
         */
106
        public static final String IMPLICIT_VAR_TYPE_NAME = "<ImplicitVarType>";
107

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

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

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

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

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

152

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

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

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

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

201
        public void removeEntity( NamedEntity ent) {
202
                IBinding key;
203
                key = entityToKey.get(ent);
6✔
204
                if (key != null) {
2✔
205
                        entityToKey.remove(ent);
5✔
206
                        keyToEntity.remove(key);
5✔
207
                }
208

209
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7✔
210
                if (l_ent != null) {
2✔
211
                        l_ent.remove(ent);
4✔
212
                }
213

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

245
                return ret;
2✔
246
        }
247

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

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

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

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

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

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

328
                if (bnd != null) {
2✔
329
                        fmx = (T) getEntityByKey(bnd);
4✔
330
                        if (fmx != null) {
2✔
331
                                return fmx;
2✔
332
                        }
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 ParametricClass 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.setGenericEntity((TParametricEntity)fmx);
3✔
370
                fmxParam.setIsStub(fmx.getIsStub());
4✔
371
            }
372
                }
373
                
374
                fmx.setTypeContainer(owner);
3✔
375
                return fmx;
2✔
376
        }
377

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

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

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

423
        ///// ensure Famix Relationships /////
424

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

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

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

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

472
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6!
473
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7✔
474
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7✔
475

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

480
                return association;
2✔
481
        }
482

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

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

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

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

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

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

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

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

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

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

590
                return ref;
2✔
591
        }
592

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

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

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

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

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

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

697

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

721

722
        ///// Special Case: ImplicitVariables /////
723

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

757
                return ret;
×
758
        }
759

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

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

799
                return fmx;
2✔
800
        }
801

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

814
                return fmx;
2✔
815
        }
816

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

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

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

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

868
                return fmx;
2✔
869
        }
870

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

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

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

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

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

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

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

936
                // bnd != null
937

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

943
                if (bnd.isArray()) {
3!
944
                        bnd = bnd.getElementType();
×
945
                }
946

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

951
                if (bnd.isEnum()) {
3!
NEW
952
                        return this.ensureFamixEnum(bnd, name, owner);
×
953
                }
954

955
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
956
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
957
                }
958
                
959
                if (bnd.isAnnotation()) {
3!
960
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
×
961
                }
962

963
                if (bnd.isInterface()) {
3✔
964
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19✔
965
                }
966

967
                if (isThrowable(bnd)) {
4✔
968
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8✔
969
                }
970
                if (bnd.isClass()) {
3✔
971
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20!
972
                }
973
                if(bnd.isWildcardType()) {
3✔
974
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8✔
975
                }
976

977
                //otherwise (none of the above)
978

979
                if (name == null) {
2✔
980
                        name = bnd.getName();
3✔
981
                }
982

983
                if (owner == null) {
2!
984
                        owner = (TWithTypes) this.ensureOwner(bnd);
5✔
985
                }
986

987
                if (bnd.isTypeVariable() ) {
3!
988
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6✔
989
                        return fmx;
2✔
990
                }
991

992
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
993
                fmx.setTypeContainer(owner);
×
994
                return fmx;
×
995
        }
996

997
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
998
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
999
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1000
        }
1001
        
1002
        public Type ensureFamixType(ITypeBinding bnd) {
1003
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1004
        }
1005

1006
        public boolean isThrowable(ITypeBinding bnd) {
1007
                if (bnd == null) {
2!
1008
                        return false;
×
1009
                }
1010
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5✔
1011
                        return true;
2✔
1012
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5✔
1013
                        return false;
2✔
1014
                }
1015
                else {
1016
                        return isThrowable(bnd.getSuperclass());
5✔
1017
                }
1018
        }
1019

1020
        /**
1021
         * Returns a Famix Class associated with the ITypeBinding.
1022
         * The Entity is created if it does not exist.
1023
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
1024
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1025
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1026
         */
1027
        @SuppressWarnings("deprecation")
1028
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1029
                Class fmx;
1030

1031
                // --------------- some special cases
1032
                if (bnd != null) {
2✔
1033
                        if (bnd.isArray()) {
3!
1034
                                bnd = bnd.getElementType();
×
1035
                        }
1036

1037
                        // for inner classes defined in generics !!! For others should not change anything
1038
                        bnd = bnd.getErasure();
3✔
1039
                }
1040

1041
                // ---------------- to avoid useless computations if we can
1042
                fmx = (Class) getEntityByKey(bnd);
5✔
1043
                if (fmx != null) {
2✔
1044
                        return fmx;
2✔
1045
                }
1046

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

1070
        // If we have java.lang.Object we should ensure we create this class
1071
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7✔
1072
                        return ensureFamixClassObject();
3✔
1073
                }
1074

1075
                // --------------- owner
1076
                if (owner == null) {
2✔
1077
                        if (bnd != null) {
2✔
1078
                                owner = ensureOwner(bnd);
4✔
1079
                        }
1080
                        /*                                owner = ensureFamixPackageDefault();
1081
                        } else {*/
1082
                }
1083

1084
                // --------------- recover from name ?
1085
                if (owner != null) {
2✔
1086
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13✔
1087
                                if (matchAndMapClass(bnd, name, owner, candidate)) {
7✔
1088
                                        fmx = candidate;
2✔
1089
                                        break;
1✔
1090
                                }
1091
                        }
1✔
1092
                }
1093

1094
                // ---------------- create
1095
                if (fmx == null) {
2✔
1096
                        if (isGeneric) {
2✔
1097
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8✔
1098
                        }
1099
                        else {
1100
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7✔
1101
                                fmx.setTypeContainer((TWithTypes)owner);
4✔
1102
                        }
1103
                }
1104

1105
                if (fmx!=null) {
2!
1106
                        // we just created it or it was not bound, so we make sure it has the right information in it
1107
                        if (bnd != null) {
2✔
1108
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1109
                        }
1110
                        TAssociation lastAssoc = null;
2✔
1111

1112
                        if (bnd != null) {
2✔
1113
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1114
                                if (supbnd != null) {
2✔
1115
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1116
                                }
1117
                                else {
1118
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8✔
1119
                                }
1120
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7✔
1121
                        }
1122
                }
1123

1124
                return fmx;
2✔
1125
        }
1126

1127
        /**
1128
         * Returns a Famix Exception associated with the ITypeBinding.
1129
         * The Entity is created if it does not exist.
1130
         * @param name -- the name of the Famix Exception (MUST NOT be null, but this is not checked)
1131
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1132
         *
1133
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1134
         */
1135
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1136
                Exception fmx;
1137

1138
                // --------------- some special cases
1139
                if (bnd != null) {
2✔
1140
                        if (bnd.isArray()) {
3!
1141
                                bnd = bnd.getElementType();
×
1142
                        }
1143

1144
                        // for inner classes defined in generics !!! For others should not change anything
1145
                        bnd = bnd.getErasure();
3✔
1146
                }
1147

1148
                // ---------------- to avoid useless computations if we can
1149
                fmx = (Exception) getEntityByKey(bnd);
5✔
1150
                if (fmx != null) {
2✔
1151
                        return fmx;
2✔
1152
                }
1153

1154
                // --------------- name
1155
                if (name == null) {
2✔
1156
                        if (bnd == null) {
2!
1157
                                return null;  // not much we can do
×
1158
                        } else if (!bnd.isAnonymous()) {
3!
1159
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5✔
1160
                        } else { // anonymous class
1161
                                if (bnd.getSuperclass() != null) {
×
1162
                                        name = bnd.getSuperclass().getName();
×
1163
                                }
1164
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1165
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1166
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1167
                                                name = bnd.getInterfaces()[0].getName();
×
1168
                                        }
1169
                                        else {
1170
                                                name = "???";
×
1171
                                        }
1172
                                }
1173
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1174
                        }
1175
                }
1176

1177
                // --------------- owner
1178
                if (owner == null) {
2✔
1179
                        if (bnd == null) {
2✔
1180
                                owner = ensureFamixPackageDefault();
4✔
1181
                        } else {
1182
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1183
                        }
1184
                }
1185

1186
                // --------------- recover from name ?
1187
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13✔
1188
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8!
1189
                                fmx = candidate;
×
1190
                                break;
×
1191
                        }
1192
                }
1✔
1193

1194
                // ---------------- create
1195
                if (fmx == null) {
2!
1196
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7✔
1197
                        fmx.setTypeContainer(owner);
3✔
1198
                }
1199

1200
        // we just created it or it was not bound, so we make sure it has the right information in it
1201
        TAssociation lastAssoc = null;
2✔
1202
        if (bnd != null) {
2✔
1203
            ITypeBinding supbnd = bnd.getSuperclass();
3✔
1204
            if (supbnd != null) {
2!
1205
                lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1206
            }
1207
            else {
NEW
1208
                lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
×
1209
            }
1210
            ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6✔
1211
        }
1212

1213
        return fmx;
2✔
1214
        }
1215

1216
        /**
1217
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1218
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
1219
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1220
         * @return the FAMIX Class or null in case of a FAMIX error
1221
         */
1222
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1223
                Interface fmx;
1224

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

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

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

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

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

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

1281
                // ---------------- create
1282
                if (fmx == null) {
2✔
1283
                        if (isGeneric) {
2✔
1284
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7✔
1285
                        }
1286
                        else {
1287
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7✔
1288
                                fmx.setTypeContainer(owner);
3✔
1289
                        }
1290
                }
1291

1292
                if (fmx!=null) {
2!
1293
                        // we just created it or it was not bound, so we make sure it has the right information in it
1294
                        if (bnd != null) {
2!
1295
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5✔
1296
                        }
1297
                        TAssociation lastAssociation = null;
2✔
1298
                        if (bnd != null) {
2!
1299
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6✔
1300
                        }
1301
                }
1302
                return fmx;
2✔
1303
        }
1304

1305
        public TThrowable asException(TType fmxType) {
1306
                if (fmxType instanceof Exception) {
3✔
1307
                        return (Exception) fmxType;
3✔
1308
                }
1309
                if(fmxType instanceof TypeParameter) {
3✔
1310
                        return (TypeParameter) fmxType;
3✔
1311
                }
1312

1313
                Exception fmxException = null;
2✔
1314
                IBinding key;
1315

1316
                try {
1317
                        key = entityToKey.get(fmxType);
6✔
1318

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

1323
                        TWithTypes owner = fmxType.getTypeContainer();
3✔
1324
                        fmxType.setTypeContainer(null);
3✔
1325
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1326

1327
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8✔
1328
                        if (fmxType instanceof TWithAttributes) {
3!
1329
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8✔
1330
                        }
1331

1332
                        if (fmxType instanceof TWithInheritances) {
3!
1333
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8✔
1334
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8✔
1335
                        }
1336
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4✔
1337
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7✔
1338
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8✔
1339
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7✔
1340
                        fmxException.setIsStub(fmxType.getIsStub());
4✔
1341
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8✔
1342
                }
1343
                catch( ConcurrentModificationException e) {
×
1344
                        e.printStackTrace();
×
1345
                }
1✔
1346

1347
                return fmxException;
2✔
1348
        }
1349

1350
        /**
1351
         * helper method, we know the type exists, ensureFamixClass will recover it
1352
         */
1353
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1354
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1355
        }
1356

1357
        /**
1358
         * helper method, we know the type exists, ensureFamixInterface will recover it
1359
         */
1360
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1361
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1362
        }
1363

1364
        /**
1365
         * helper method, we know the type exists, ensureFamixInterface will recover it
1366
         */
1367
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1368
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1369
        }
1370

1371
        /**
1372
         * Ensures a famix entity for the owner of a binding.<br>
1373
         * This owner can be a method, a class or a namespace
1374
         * @param bnd -- binding for the owned entity
1375
         * @return a famix entity for the owner
1376
         */
1377
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1378
                TNamedEntity owner;
1379
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3✔
1380
                if (parentMtd != null) {
2✔
1381
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5✔
1382
                }
1383
                else {
1384
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3✔
1385
                        if (parentClass != null) {
2✔
1386
                owner = this.ensureFamixType(parentClass);
5✔
1387
            }
1388
                        else {
1389
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1390
                                if (parentPckg != null) {
2!
1391
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1392
                                } else {
1393
                                        owner = this.ensureFamixPackageDefault();
×
1394
                                }
1395
                        }
1396
                }
1397
                return owner;
2✔
1398
        }
1399

1400

1401
        /**
1402
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1403
         * We assume that PrimitiveType must be uniq for a given name
1404
         * @param name -- the name of the FAMIX PrimitiveType
1405
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1406
         */
1407
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1408
                if (name == null) {
2✔
1409
                        if (bnd == null) {
2!
1410
                                return null;
×
1411
                        } else {
1412
                                name = bnd.getName();
3✔
1413
                        }
1414
                }
1415
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7✔
1416
        }
1417

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

1421
                // --------------- to avoid useless computations if we can
1422
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1423
                if (fmx != null) {
2✔
1424
                        return fmx;
2✔
1425
                }
1426

1427
                // --------------- name
1428
                if (name == null) {
2✔
1429
                        if (bnd == null) {
2!
1430
                                return null;
×
1431
                        }
1432
                        else {
1433
                                name = bnd.getName();
3✔
1434
                        }
1435
                }
1436

1437
                // --------------- owner
1438
                if (owner == null) {
2✔
1439
                        if (bnd == null) {
2!
1440
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1441
                        } else {
1442
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1443
                        }
1444
                }
1445

1446
                // --------------- recover from name ?
1447
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1448
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1449
                                fmx = candidate;
×
1450
                                break;
×
1451
                        }
1452
                }
×
1453

1454
                if (fmx == null) {
2!
1455
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1456
                        fmx.setTypeContainer(owner);
3✔
1457
                }
1458

1459
                if (bnd != null) {
2!
1460
                        setVisibility(fmx, bnd.getModifiers());
5✔
1461
                }
1462

1463
                return fmx;
2✔
1464
        }
1465

1466
        /**
1467
         * helper method, we know the type exists, ensureFamixEnum will recover it
1468
         */
1469
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1470
                return ensureFamixEnum(bnd, name, owner);
6✔
1471
        }
1472

1473
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1474
                EnumValue fmx;
1475

1476
                // --------------- to avoid useless computations if we can
1477
                fmx = (EnumValue)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) {
×
1485
                                return null;
×
1486
                        }
1487
                        else {
1488
                                name = bnd.getName();
×
1489
                        }
1490
                }
1491

1492
                // --------------- owner
1493
                if (owner == null) {
2✔
1494
                        if (bnd == null) {
2!
1495
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1496
                        }
1497
                        else {
1498
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1499
                        }
1500
                }
1501

1502
                // --------------- recover from name ?
1503
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
1504
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1505
                                fmx = candidate;
×
1506
                                break;
×
1507
                        }
1508
                }
×
1509
                if (fmx == null) {
2!
1510
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1511
                        fmx.setParentEnum(owner);
3✔
1512
                }
1513

1514
        fmx.setParentEnum(owner);
3✔
1515

1516
        return fmx;
2✔
1517
        }
1518

1519
    /**
1520
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1521
         */
1522
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1523
                AnnotationType fmx;
1524

1525
                // --------------- to avoid useless computations if we can
1526
                fmx = (AnnotationType)getEntityByKey(bnd);
5✔
1527
                if (fmx != null) {
2✔
1528
                        return fmx;
2✔
1529
                }
1530

1531
                // --------------- name
1532
                if (name == null) {
2✔
1533
                        if (bnd == null) {
2!
1534
                                return null;
×
1535
                        }
1536
                        else {
1537
                                name = bnd.getName();
3✔
1538
                        }
1539
                }
1540

1541
                // --------------- owner
1542
                if (owner == null) {
2✔
1543
                        if (bnd == null) {
2!
1544
                                owner = ensureFamixPackageDefault();
×
1545
                        }
1546
                        else {
1547
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1548
                                if (parentPckg != null) {
2!
1549
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1550
                                } else {
1551
                                        owner = this.ensureFamixPackageDefault();
×
1552
                                }
1553
                        }
1554
                }
1555

1556
                // --------------- recover from name ?
1557
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1558
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1559
                                fmx = candidate;
2✔
1560
                                break;
1✔
1561
                        }
1562
                }
1✔
1563

1564
                // --------------- create
1565
                if (fmx == null) {
2✔
1566
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1567
                        fmx.setAnnotationTypesContainer(owner);
3✔
1568
                }
1569

1570
                if (bnd != null) {
2!
1571
                        // Not supported in Famix
1572

1573
                        // setVisibility(fmx, bnd.getModifiers());
1574
                }
1575

1576
                return fmx;
2✔
1577
        }
1578

1579
        /**
1580
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1581
         */
1582
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1583
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1584
        }
1585

1586
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1587
                AnnotationTypeAttribute fmx = null;
2✔
1588

1589
                // --------------- to avoid useless computations if we can
1590
                fmx = (AnnotationTypeAttribute)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) {
×
1598
                                return null;
×
1599
                        }
1600
                        else {
1601
                                name = bnd.getName();
×
1602
                        }
1603
                }
1604

1605
                // --------------- owner
1606
                if (owner == null) {
2!
1607
                        if (bnd == null) {
×
1608
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1609
                        }
1610
                        else {
1611
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1612
                                if (parentType != null) {
×
1613
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1614
                                }
1615
                                else  {
1616
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1617
                                }
1618
                        }
1619
                }
1620

1621
                // --------------- recover from name ?
1622
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13✔
1623
                        // JDT treats annotation type attributes as methods ...
1624
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1625
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11!
1626
                                fmx = candidate;
×
1627
                                break;
×
1628
                        }
1629
                        // if the binding is null, the annotationTypeAttribute migth have been created
1630
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2!
1631
                                fmx = candidate;
×
1632
                                break;
×
1633
                        }
1634
                }
1✔
1635

1636
                if (fmx == null) {
2!
1637
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1638
                        fmx.setParentType(owner);
3✔
1639
                }
1640

1641
                if (bnd != null) {
2!
1642
                        // Not suopp
1643

1644
                        // setVisibility(fmx, bnd.getModifiers());
1645
                }
1646

1647
                return fmx;
2✔
1648
        }
1649

1650
        /**
1651
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1652
         */
1653
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1654
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6✔
1655
        }
1656
        
1657
        
1658
        /**
1659
         * Returns a FAMIX Wildcard with its bounds
1660
         * @param bnd
1661
         * @param name
1662
         * @param owner
1663
         * @return
1664
         */
1665
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1666
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8✔
1667
                if(bnd.getBound() != null) {
3✔
1668
                        Type bound = this.ensureFamixType(bnd.getBound());
5✔
1669
                        if(bnd.isUpperbound()) {
3✔
1670
                                fmx.setUpperBound(bound);
3✔
1671
                                bound.addUpperBoundedWildcards(fmx);
4✔
1672
                        }else{
1673
                                fmx.setLowerBound(bound);
3✔
1674
                                bound.addLowerBoundedWildcards(fmx);
3✔
1675
                        }
1676
                }
1677
                return fmx;
2✔
1678
        }
1679

1680
        /**
1681
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1682
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1683
         * @param name -- the name of the Famix TypeParameter
1684
         * @return the Famix TypeParameter or null in case of a Famix error
1685
         */
1686
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1687
                TypeParameter fmx;
1688

1689
                // --------------- to avoid useless computations if we can
1690
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1691
                if (fmx != null) {
2✔
1692
                        return fmx;
2✔
1693
                }
1694

1695
                // --------------- name
1696
                if (name == null) {
2✔
1697
                        if (bnd == null) {
2!
1698
                                return null;
×
1699
                        }
1700
                        else {
1701
                                name = bnd.getName();
3✔
1702
                        }
1703
                }
1704

1705
                // --------------- owner
1706
                if (owner == null && bnd != null) {
2!
NEW
1707
            if (bnd.getDeclaringClass() != null) {
×
NEW
1708
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
NEW
1709
            } else if(bnd.getDeclaringMethod() != null) {
×
NEW
1710
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1711
            }
1712
                }
1713

1714
                // --------------- recover from name ?
1715
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1716
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1717
                                fmx = (TypeParameter) candidate;
3✔
1718
                                break;
1✔
1719
                        }
1720
                }
1✔
1721

1722
                // --------------- create
1723
                if (fmx == null) {
2✔
1724
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1725
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1726
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5✔
1727
                                fmx.setUpperBound(upperBound);
3✔
1728
                        }
1729
                        if(bnd != null) {
2✔
1730
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
1731
                    Type upperBound = ensureFamixType(intbnd);
4✔
1732
                    fmx.setUpperBound(upperBound);
3✔
1733
                }
1734
            }
1735
                        fmx.setTypeContainer(owner);
3✔
1736
                }
1737

1738
                return fmx;
2✔
1739
        }
1740

1741
        /**
1742
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1743
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1744
         *
1745
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1746
         * @param name      of the package
1747
         * @param owner     of the package
1748
         * @param candidate -- a Famix Entity
1749
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1750
         */
1751
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1752
                if (!(candidate instanceof Package)) {
3!
1753
                        return false;
×
1754
                }
1755

1756
                // check whether bnd and candidate are already bound
1757
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1758
                if (res == CheckResult.MATCH) {
3✔
1759
                        return true;
2✔
1760
                } else if (res == CheckResult.FAIL) {
3!
1761
                        return false;
×
1762
                }
1763

1764
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1765
                        return false;
2✔
1766
                }
1767

1768
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1769
                conditionalMapToKey(bnd, candidate);
4✔
1770
                return true;
2✔
1771
        }
1772

1773
        /**
1774
         * Checks whether the existing unmapped Famix Type matches the binding.
1775
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1776
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1777
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1778
         * @param name of the type
1779
         * @param owner of the type
1780
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1781
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1782
         */
1783
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1784
                if (! (candidate instanceof Type) ) {
3!
1785
                        return false;
×
1786
                }
1787

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

1797
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
1798
                                bnd = bnd.getElementType();
×
1799
                }
1800

1801
                // checking names
1802
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
1803
                        name = bnd.getErasure().getName();
×
1804
                }
1805
                else if (bnd != null) {
2✔
1806
                        name = bnd.getName();
3✔
1807
                }
1808
                // else name = name
1809
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1810
                        return false;
2✔
1811
                }
1812

1813
                // special case of primitive types
1814
                if (candidate instanceof PrimitiveType) {
3!
1815
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1816
                                // names are equal so it's OK
1817
                                conditionalMapToKey(bnd, candidate);
×
1818
                                return true;
×
1819
                        }
1820
                        else if ( (bnd == null) && (owner == null) ) {
×
1821
                                return true;
×
1822
                        }
1823
                }
1824

1825
                // check owners without bnd
1826
                if (bnd == null) {
2✔
1827
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1828
                }
1829

1830
                // check owners with bnd
1831
                // type is an annotation
1832
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1833
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1834
                                conditionalMapToKey(bnd, candidate);
4✔
1835
                                return true;
2✔
1836
                        } else {
1837
                                return false;
×
1838
                        }
1839
                }
1840

1841
                // check owners with bnd
1842
                // type is a Parameterized type
1843
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
1844
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1845
                }
1846

1847
                // check owners with bnd
1848
                // type is an Enum
1849
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
1850
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1851
                }
1852

1853
                // check owners with bnd
1854
                // type is something elae (a class or interface)
1855
                // Annotation are interfaces too, so we should check this one after isAnnotation
1856
                if ( bnd.isClass()) {
3!
1857
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1858
                }
1859

1860
                if(bnd.isInterface()) {
3!
1861
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1862
                }
1863

1864
                return false;
2✔
1865
        }
1866

1867
        /**
1868
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1869
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1870
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1871
         * @param name of the class
1872
         * @param owner of the class
1873
         * @param candidate -- a Famix Entity
1874
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1875
         */
1876
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1877
                if (!(candidate instanceof Class)) {
3!
1878
                        return false;
×
1879
                }
1880

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

1889
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1890
                        return false;
×
1891
                }
1892

1893
                // checking owner
1894
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1895
        }
1896

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

1911
                // check whether bnd and candidate are already bound
1912
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1913
                if (res == CheckResult.MATCH) {
3!
1914
                        return true;
×
1915
                } else if (res == CheckResult.FAIL) {
3✔
1916
                        return false;
2✔
1917
                }
1918

1919
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1920
                        return false;
×
1921
                }
1922

1923
                // checking owner
1924
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
1925
        }
1926

1927
        /**
1928
         * Checks whether the existing unmapped Famix "Method" matches the binding.
1929
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
1930
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
1931
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1932
         * @param sig -- signature of the method
1933
         * @param retTyp -- return type of the method
1934
         * @param owner of the method
1935
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
1936
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1937
         */
1938
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
1939
                if (! (candidate instanceof Method) ) {
3✔
1940
                        return false;
2✔
1941
                }
1942

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

1952
                // checking names
1953
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
1954
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1955
                        return false;
×
1956
                }
1957

1958
                // for methods, the name is not enough, we must test the signature also
1959
                // but not for AnnotationTypeAttribute
1960

1961
                        if (bnd != null) {
2✔
1962
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
1963
                        }
1964
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
1965
                                return false;
2✔
1966
                        }
1967

1968
                        // and still for method, must also check the return type
1969
                        if (bnd != null) {
2✔
1970
                                if (bnd.isConstructor()) {
3!
1971
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
×
1972
                                                return false;
×
1973
                                        }
1974
                                        // else OK for now
1975
                                }
1976
                                else { // not a constructor
1977
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4!
1978
                                                return false;
×
1979
                                        }
1980
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10!
1981
                                                return false;
×
1982
                                        }
1983
                                        // else OK for now
1984
                                }
1985
                        }
1986
                        else {  // bnd == null
1987
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2!
1988
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4✔
1989
                                                return false;
2✔
1990
                                        }
1991
                                        // else OK for now
1992
                                } else { // (ret != null)  i.e. not a constructor
1993
                                        if (((Method) candidate).getDeclaredType() == null) {
×
1994
                                                return false;
×
1995
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
1996
                                                return false;
×
1997
                                        }
1998
                                        // else OK for now
1999
                                }
2000
                        }
2001

2002

2003
                // check owner
2004
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2005
                        conditionalMapToKey(bnd, candidate);
4✔
2006
                        return true;
2✔
2007
                } else {
2008
                        return false;
2✔
2009
                }
2010
        }
2011

2012
        /**
2013
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2014
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2015
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2016
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2017
         * @param name of the variable
2018
         * @param owner of the variable
2019
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2020
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2021
         */
2022
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2023
                if (!(candidate instanceof TStructuralEntity)) {
3!
2024
                        return false;
×
2025
                }
2026

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

2035
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2036
                        return false;
×
2037
                }
2038

2039
                // check owner
2040
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2041

2042
                // local variable or parameter ?
2043
                // owner is a Method? (for example in case of an anonymous class)
2044
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11✔
2045
                if (res == CheckResult.FAIL) {
3✔
2046
                        return false;
2✔
2047
                } else if (res == CheckResult.MATCH) {
3!
2048
                        conditionalMapToKey(bnd, candidate);
×
2049
                        return true;
×
2050
                }
2051

2052
                // check owner
2053
                // <anArray>.length field?
2054
                if (name.equals("length")) {
4!
2055
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2056
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2057
                        if (isArrayLengthField) {
×
2058
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2059
                                        conditionalMapToKey(bnd, candidate);
×
2060
                                        return true;
×
2061
                                }
2062
                                else {
2063
                                        return false;
×
2064
                                }
2065
                        }
2066
                }
2067

2068
                // check owner
2069
                // "normal" field?
2070
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2071
                if (res == CheckResult.MATCH) {
3!
2072
                        conditionalMapToKey(bnd, candidate);
4✔
2073
                        return true;
2✔
2074
                }
2075
                return false;
×
2076
        }
2077

2078
        /**
2079
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2080
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2081
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2082
         * @param owner -- the owner of the type
2083
         * @param candidate -- a Famix Entity
2084
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2085
         */
2086
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2087
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4✔
2088

2089
                // owner is a Method? (for example in case of an anonymous class)
2090
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2091
                if (res == CheckResult.MATCH) {
3!
2092
                        conditionalMapToKey(bnd, candidate);
×
2093
                        return true;
×
2094
                } else if (res == CheckResult.FAIL) {
3!
2095
                        return false;
×
2096
                }
2097

2098
                // owner is a class ?
2099
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2100
                if (res == CheckResult.MATCH) {
3✔
2101
                        conditionalMapToKey(bnd, candidate);
4✔
2102
                        return true;
2✔
2103
                }
2104
                else if (res == CheckResult.FAIL) {
3✔
2105
                        return false;
2✔
2106
                }
2107

2108
                // owner must be a package
2109
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2110
                        conditionalMapToKey(bnd, candidate);
4✔
2111
                        return true;
2✔
2112
                }
2113
                return false;
2✔
2114
        }
2115

2116
        /**
2117
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2118
         * @param methBnd
2119
         * @param owner
2120
         * @param candidateOwner
2121
         * @return a {@link CheckResult}
2122
         */
2123
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2124
                if ((methBnd != null) || (owner instanceof Method)) {
5!
2125
                        if (!(candidateOwner instanceof Method)) {
3!
2126
                                return CheckResult.FAIL;
×
2127
                        }
2128

2129
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2130
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2131
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2132

2133
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
2134
                                return CheckResult.MATCH;
×
2135
                        } else {
2136
                                return CheckResult.FAIL;
2✔
2137
                        }
2138
                }
2139
                return CheckResult.UNDECIDED;
2✔
2140
        }
2141

2142
        /**
2143
         * @param typBnd
2144
         * @param owner
2145
         * @param candidateOwner
2146
         * @return a {@link CheckResult}
2147
         */
2148
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2149
                if ((typBnd != null) || (owner instanceof Type)) {
5✔
2150
                        if (!(candidateOwner instanceof Type)) {
3✔
2151
                                return CheckResult.FAIL;
2✔
2152
                        }
2153

2154
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2155
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2156

2157
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2158
                                return CheckResult.MATCH;
2✔
2159
                        } else {
2160
                                return CheckResult.FAIL;
2✔
2161
                        }
2162
                }
2163
                return CheckResult.UNDECIDED;
2✔
2164
        }
2165

2166
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2167
                if ((pckgBnd != null) || (owner instanceof Package)) {
5!
2168
                        if (!(candidateOwner instanceof Package)) {
3!
2169
                                return CheckResult.FAIL;
×
2170
                        }
2171

2172
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2173
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2174

2175
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2176
                                return CheckResult.MATCH;
2✔
2177
                        } else {
2178
                                return CheckResult.FAIL;
2✔
2179
                        }
2180
                }
2181
                return CheckResult.UNDECIDED;
×
2182
        }
2183

2184
        /**
2185
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2186
         * 'name' and 'bnd' cannot be null together
2187
         * @param bnd -- binding associated with the entity may be null
2188
         * @param name -- name of the entity may be null
2189
         * @param candidate
2190
         * @return true if names match, false if not
2191
         */
2192
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2193
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8!
2194
                        return CheckResult.FAIL;
×
2195
                }
2196
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9!
2197
                        return CheckResult.FAIL;
2✔
2198
                }
2199
                else {
2200
                        return CheckResult.MATCH;
2✔
2201
                }
2202
        }
2203

2204
        /**
2205
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2206
         * @param key
2207
         * @param candidate
2208
         * @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>
2209
         */
2210
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2211
                if (key == null) {
2✔
2212
                        return CheckResult.UNDECIDED;
2✔
2213
                }
2214

2215
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2216
                if (bound == candidate) {
3✔
2217
                        return CheckResult.MATCH;
2✔
2218
                }
2219
                else if (bound != null) {
2✔
2220
                        return CheckResult.FAIL;
2✔
2221
                }
2222
                else if (getEntityKey(candidate) != null) {
4✔
2223
                        // candidate already bound, and not to this binding
2224
                        return CheckResult.FAIL;
2✔
2225
                }
2226
                else {
2227
                        return CheckResult.UNDECIDED;
2✔
2228
                }
2229
        }
2230

2231
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2232
                if (bnd != null) {
2✔
2233
                        mapEntityToKey(bnd, ent);
4✔
2234
                }
2235
        }
1✔
2236

2237
        public Method ensureFamixMethod(IMethodBinding bnd) {
2238
                return ensureFamixMethod(
8✔
2239
                                bnd,
2240
                                /*name*/null,
2241
                                /*paramsType*/null,
2242
                                /*returnType*/null,
2243
                                /*owner*/null,
2244
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2245
        }
2246

2247
        /**
2248
         * Returns a Famix Method associated with the IMethodBinding. The Entity is created if it does not exist.
2249
         * The Entity is created if it does not exist.
2250
         * @param name -- the name of the FAMIX Method (MUST NOT be null, but this is not checked)
2251
         * @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)
2252
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2253
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2254
         */
2255
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, Type ret, TWithMethods owner, int modifiers) {
2256
                Method fmx;
2257
                String sig;
2258
                boolean delayedRetTyp;
2259

2260
                // --------------- to avoid useless computations if we can
2261
                fmx = (Method)getEntityByKey(bnd);
5✔
2262
                if (fmx != null) {
2✔
2263
                        return fmx;
2✔
2264
                }
2265

2266
                // --------------- name
2267
                if (name == null) {
2✔
2268
                        if (bnd == null) {
2✔
2269
                                return null;
2✔
2270
                        }
2271
                        else {
2272
                                name = bnd.getName();
3✔
2273
                        }
2274
                }
2275

2276
                // --------------- signature
2277
                sig = name + "(";
3✔
2278
                 if (bnd != null) {
2✔
2279
                    sig += signatureParamsFromBinding(bnd);
7✔
2280
                }
2281
        else if (paramTypes != null) {
2!
2282
                        sig += signatureParamsFromStringCollection(paramTypes);
7✔
2283
                }
2284
                else {
2285
                        sig += "???";
×
2286
                }
2287
                sig += ")";
3✔
2288

2289
                // --------------- return type
2290
                delayedRetTyp = false;
2✔
2291
                ITypeBinding retTypBnd = null;
2✔
2292
                if (ret == null) {
2!
2293
                        if (bnd != null) {
2✔
2294
                // must create the return type
2295
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2296
                // we need T to create the method and the method to create T ...
2297
                // so we need to test the situation and deal with it
2298
                retTypBnd = bnd.getReturnType();
3✔
2299
                if (retTypBnd != null) {
2✔
2300
                    if (retTypBnd.isArray()) {
3✔
2301
                        retTypBnd = retTypBnd.getElementType();
3✔
2302
                    }
2303
                }
2304

2305
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2306
                    delayedRetTyp = true;
3✔
2307
                }
2308
                else {
2309
                    ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2310
                }
2311
                        }
2312
                }
2313

2314
                // --------------- owner
2315
                if (owner == null) {
2✔
2316
                        if (bnd == null) {
2✔
2317
                                owner = ensureFamixClassStubOwner();
4✔
2318
                        }
2319
                        else {
2320
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2321
                                if (classBnd != null) {
2!
2322
                                        owner = ensureFamixType(classBnd);
5✔
2323
                                }
2324
                                else {
2325
                                        owner = ensureFamixClassStubOwner();
×
2326
                                }
2327
                        }
2328
                }
2329

2330
                // --------------- recover from name ?
2331
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2332
                        if (matchAndMapMethod(bnd, sig, ret, (TNamedEntity) owner, candidate)) {
9✔
2333
                                fmx = candidate;
2✔
2334
                                break;
1✔
2335
                        }
2336
                }
1✔
2337

2338
                if (fmx == null) {
2✔
2339
                        if(bnd != null && bnd.isGenericMethod()) {
5✔
2340
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7✔
2341
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18✔
2342
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6✔
2343
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4✔
2344
                                }
2345
                        // parameterized method binding = when the method is the target of an invocation.
2346
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5!
NEW
2347
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
×
2348
                        }else{
2349
                                fmx = ensureFamixEntity(Method.class, bnd, name);
7✔
2350
                        }
2351
                        
2352
                        fmx.setSignature(sig);
3✔
2353
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7✔
2354
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6✔
2355
                        fmx.setParentType(owner);
3✔
2356
                }
2357

2358
        setMethodModifiers(fmx, modifiers);
4✔
2359
        // if it's a constructor
2360
        if (fmx.getName().equals(Util.getOwner(fmx).getName())) {
7✔
2361
            fmx.setKind(CONSTRUCTOR_KIND_MARKER);
3✔
2362
        }
2363

2364
        //If it has the #default keywork, we mark it as default implementation
2365
        if (Modifier.isDefault(modifiers)) {
3✔
2366
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3✔
2367
        }
2368

2369
        if (delayedRetTyp) {
2✔
2370
                        int retTypModifiers = retTypBnd.getModifiers();
3✔
2371
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3✔
2372
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2373
                }
2374

2375
                return fmx;
2✔
2376
        }
2377

2378
        /**
2379
         * Creates or recovers a stub Famix Method
2380
         * @param name of the method
2381
         * @return the Famix Method
2382
         */
2383
        public Method ensureFamixStubMethod(String name) {
NEW
2384
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2385
        }
2386

2387
        public void setAttributeModifiers(Attribute fmx, int mod) {
2388
                setCommonModifiers(fmx, mod);
4✔
2389
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2390
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2391
        }
1✔
2392

2393
        public void setMethodModifiers(Method fmx, int mod) {
2394
                setCommonModifiers(fmx, mod);
4✔
2395
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2396
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2397
        }
1✔
2398

2399
        public void setClassModifiers(Class fmx, int mod) {
2400
                setCommonModifiers(fmx, mod);
4✔
2401
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2402
        }
1✔
2403

2404
        public void setInterfaceModifiers(Interface fmx, int mod) {
2405
                setCommonModifiers(fmx, mod);
4✔
2406
        }
1✔
2407

2408
        private void setCommonModifiers(Entity fmx, int mod) {
2409
                setVisibility((THasVisibility)fmx, mod);
5✔
2410
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2411
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2412
        }
1✔
2413

2414
        /**
2415
         * Sets the visibility of a FamixNamedEntity
2416
         *
2417
         * @param fmx -- the FamixNamedEntity
2418
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2419
         */
2420
        public void setVisibility(THasVisibility fmx, int mod) {
2421
                if (Modifier.isPublic(mod)) {
3✔
2422
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2423
                } else if (Modifier.isPrivate(mod)) {
3✔
2424
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2425
                } else if (Modifier.isProtected(mod)) {
3✔
2426
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2427
                } else {
2428
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2429
                }
2430
        }
1✔
2431

2432
        /**
2433
         * Returns a Famix Attribute associated with the IVariableBinding.
2434
         * The Entity is created if it does not exist.<br>
2435
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2436
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2437
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2438
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2439
         */
2440
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2441
                Attribute fmx;
2442

2443
                // --------------- to avoid useless computations if we can
2444
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2445
                if (fmx != null) {
2✔
2446
                        return fmx;
2✔
2447
                }
2448

2449
                // --------------- name
2450
                if (name == null) {
2!
2451
                        if (bnd == null) {
×
2452
                                return null;
×
2453
                        }
2454
                        else {
2455
                                name = bnd.getName();
×
2456
                        }
2457
                }
2458

2459
                // --------------- owner
2460
                if (owner == null) {
2✔
2461
                        if (bnd == null) {
2!
2462
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2463
                        }
2464
                        else {
2465
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2466
                                        // Declaring class is the generic one if the class is parametric.
2467
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2468
                                } else {
2469
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2470
                                }
2471
                        }
2472
                }
2473

2474
                // --------------- recover from name ?
2475
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2476
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2477
                                fmx = candidate;
2✔
2478
                                break;
1✔
2479
                        }
2480
                }
1✔
2481

2482
                if (fmx == null) {
2✔
2483
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2484
                        fmx.setParentType( owner);
3✔
2485
                }
2486

2487
        fmx.setParentType(owner);
3✔
2488
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2489
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2490
        if (bnd != null) {
2✔
2491
            int mod = bnd.getModifiers();
3✔
2492
            setAttributeModifiers(fmx, mod);
4✔
2493
        }
2494

2495
        return fmx;
2✔
2496
        }
2497

2498
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2499
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2500
        }
2501

2502
        /**
2503
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2504
         */
2505
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2506
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2507
        }
2508

2509
        /**
2510
         * Returns a Famix Parameter associated with the IVariableBinding.
2511
         * The Entity is created if it does not exist.<br>
2512
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2513
         */
2514
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2515
                Parameter fmx = null;
2✔
2516

2517
                // --------------- to avoid useless computations if we can
2518
                try {
2519
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2520
                }catch(Throwable e) {
×
2521
                        e.printStackTrace();
×
2522
                }
1✔
2523
                if (fmx != null) {
2✔
2524
                        return fmx;
2✔
2525
                }
2526

2527
                // --------------- name
2528
                if (name == null) {
2!
2529
                        if (bnd == null) {
×
2530
                                return null;
×
2531
                        }
2532
                        else {
2533
                                name = bnd.getName();
×
2534
                        }
2535
                }
2536

2537
                // --------------- owner
2538
                if (tMethod == null) {
2!
2539
                        if (bnd == null) {
×
2540
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2541
                        }
2542
                        else {
2543
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2544
                        }
2545
                }
2546

2547
                // --------------- recover from name ?
2548
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2549
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
2550
                                fmx = candidate;
×
2551
                                break;
×
2552
                        }
2553
                }
1✔
2554

2555
                if (fmx == null) {
2!
2556
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2557
                }
2558

2559
                if (fmx != null) {
2!
2560
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2561
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2562
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2563
                }
2564

2565
                return fmx;
2✔
2566
        }
2567

2568
    /**
2569
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2570
         * The Entity is created if it does not exist.<br>
2571
         * @param name -- the name of the FAMIX LocalVariable
2572
         * @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
2573
         */
2574
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2575
                LocalVariable fmx;
2576

2577
                // --------------- to avoid useless computations if we can
2578
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2579
                if (fmx != null) {
2!
2580
                        return fmx;
×
2581
                }
2582

2583
                // --------------- name
2584
                if (name == null) {
2!
2585
                        if (bnd == null) {
×
2586
                                return null;
×
2587
                        }
2588
                        else {
2589
                                name = bnd.getName();
×
2590
                        }
2591
                }
2592

2593
                // --------------- owner
2594
                if (owner == null) {
2!
2595
                        if (bnd == null) {
×
2596
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2597
                        }
2598
                        else {
2599
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2600
                        }
2601
                }
2602

2603
                // --------------- recover from name ?
2604
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2605
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
2606
                                fmx = candidate;
×
2607
                                break;
×
2608
                        }
2609
                }
1✔
2610

2611
                if (fmx == null) {
2!
2612
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2613
                        fmx.setParentBehaviouralEntity(owner);
3✔
2614
                }
2615

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

2619
        return fmx;
2✔
2620
        }
2621

2622
    /**
2623
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2624
         * If this ImplicitVariable does not exist yet, it is created
2625
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2626
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2627
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2628
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2629
         */
2630
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2631
                ImplicitVariable fmx;
2632
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7✔
2633
                fmx.setParentBehaviouralEntity(tMethod);
3✔
2634
                return fmx;
2✔
2635
        }
2636

2637
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2638
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2639
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2640
        }
2641

2642
        /**
2643
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2644
         * @param jCmt -- the content (String) of the comment 
2645
         * @param owner -- the entity that is commented
2646
         * @return the Famix Comment
2647
         */
2648
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2649
                Comment cmt = null;
2✔
2650

2651
                if ( (jCmt != null) && (owner != null) ) {
4!
2652
                        
2653
                        cmt = new Comment();
4✔
2654
                        addSourceAnchor(cmt, jCmt);
5✔
2655
                        famixRepoAdd(cmt);
3✔
2656
                        cmt.setCommentedEntity(owner);
3✔
2657
                }
2658

2659
                return cmt;
2✔
2660
        }
2661

2662
        /**
2663
         * Creates and returns a Famix Comment and associates it with an Entity
2664
         * @param jCmt -- the content (String) of the comment 
2665
         * @param owner -- the entity that is commented
2666
         * @param content -- the text of the comment
2667
         * @return the Famix Comment
2668
         */
2669
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2670
                Comment cmt = null;
2✔
2671

2672
                if ( (jCmt != null) && (owner != null) ) {
4!
2673
                        cmt = new Comment();
4✔
2674
                        cmt.setContent(content );
3✔
2675
                        famixRepoAdd(cmt);
3✔
2676
                        cmt.setCommentedEntity(owner);
3✔
2677
                }
2678

2679
                return cmt;
2✔
2680
        }
2681

2682
        /**
2683
         * Adds location information to a Famix Entity.
2684
         * 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.
2685
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2686
         * @param fmx -- Famix Entity to add the anchor to
2687
         * @param node -- JDT ASTNode, where the information is extracted
2688
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2689
         */
2690
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2691
                IndexedFileAnchor fa;
2692

2693
                fa = createIndexedFileAnchor(node);
4✔
2694
                if ((fmx != null) && (fa != null)) {
4!
2695
                        fmx.setSourceAnchor(fa);
3✔
2696
                        famixRepoAdd(fa);
3✔
2697
                }
2698

2699
                return fa;
2✔
2700
        }
2701

2702
        /**
2703
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2704
         */
2705
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2706
                IndexedFileAnchor fa;
2707

2708
                fa = createIndexedFileAnchor(node);
4✔
2709
                if ((fmx != null) && (fa != null)) {
4!
2710

2711
                        // may change the positions
2712
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2713
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2714
                        if (node.getName() != null) {
3!
2715
                                methodDeclarationModifiers.add(node.getName());
5✔
2716
                        }
2717
                        if (node.getReturnType2() != null) {
3✔
2718
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2719
                        }
2720
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2721
                        int end = node.getStartPosition() + node.getLength();
6✔
2722

2723
                        fa.setStartPos(beg);
4✔
2724
                        fa.setEndPos(end);
4✔
2725

2726
                        fmx.setSourceAnchor(fa);
3✔
2727
                        famixRepoAdd(fa);
3✔
2728
                }
2729

2730
                return fa;
2✔
2731
        }
2732

2733
        /**
2734
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2735
         * Information returned in the form of an IndexedFileAnchor
2736
         */
2737
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2738
                IndexedFileAnchor fa;
2739
                
2740
                if (node == null) {
2!
2741
                        return null;
×
2742
                }
2743

2744
                // position in source file
2745
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2746
                int end = beg + node.getLength() - 1;
7✔
2747

2748
                // find source Compilation Unit
2749
                // there is a special case for the JDT Comment Nodes
2750
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2751
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2752
                } else {
2753
                        node = node.getRoot();
3✔
2754
                }
2755

2756
                fa = new IndexedFileAnchor();
4✔
2757
                fa.setStartPos(beg);
4✔
2758
                fa.setEndPos(end);
4✔
2759

2760
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6✔
2761

2762
                return fa;
2✔
2763
        }
2764

2765
        /**
2766
         * Creates or recovers the Famix Class for "Object".
2767
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2768
         *
2769
         * @return a Famix class for "Object"
2770
         */
2771
        public Class ensureFamixClassObject() {
2772
        // In the past we used #ensureFamixUniqEntity but that does not check that the parent package is right and we got some Object from other packages than java.lang...
2773
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5✔
2774

2775
        for (Class entity : objects) {
10✔
2776
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2777
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7✔
2778
                    return entity;
2✔
2779
                }
2780
        }
1✔
2781

2782
        Class fmx = createFamixEntity(Class.class, "Object");
6✔
2783
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2784
                return fmx;
2✔
2785
        }
2786

2787
        /**
2788
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2789
         */
2790
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2791
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2792
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2793

2794
                if (fmx != null) {
2!
2795
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2796
                }
2797

2798
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
NEW
2799
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
2800
                }
2801

2802
                return fmx;
2✔
2803
        }
2804

2805
        public Class getFamixMetaClass(ITypeBinding bnd) {
2806
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2807
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2808
        }
2809

2810
        /**
2811
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
2812
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
2813
         * JDT does not create a binding for these classes, so we create a stub one here.
2814
         *
2815
         * @return a Famix class
2816
         */
2817
        public Class ensureFamixClassArray() {
2818
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
2819
                if (fmx != null) {
×
NEW
2820
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
×
2821
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
2822

2823
                        // may be not needed anymore now that we use modifiers
2824
                        /*fmx.setIsAbstract(Boolean.FALSE);
2825
                        fmx.setIsFinal(Boolean.FALSE);
2826
                        fmx.setIsInterface(Boolean.FALSE); 
2827
                        fmx.setIsPrivate(Boolean.FALSE);
2828
                        fmx.setIsProtected(Boolean.FALSE);*/
2829
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2830
                }
2831

2832
                return fmx;
×
2833
        }
2834

2835
        public String removeLastPartOfPackageName(String qualifiedName) {
2836
                String ret;
2837
                int last = qualifiedName.lastIndexOf('.');
4✔
2838
                if (last > 0) {
2✔
2839
                        // recursively creating the parent
2840
                        ret = qualifiedName.substring(0, last);
6✔
2841
                }
2842
                else {
2843
                        ret = "";
2✔
2844
                }
2845

2846
                return ret;
2✔
2847
        }
2848

2849
        /** Generates the list of parameters for a method signature
2850
         * @return a string
2851
         */
2852
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2853
                boolean first = true;
2✔
2854
                String sig = "";
2✔
2855

2856
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2857
                        if (first) {
2✔
2858
                                sig = parBnd.getName();
3✔
2859
                                first = false;
3✔
2860
                        }
2861
                        else {
2862
                                sig += "," + parBnd.getName();
5✔
2863
                        }
2864
                }
2865
                return sig;
2✔
2866
        }
2867

2868
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2869
                boolean first = true;
2✔
2870
                String sig = "";
2✔
2871

2872
                for (String t : paramTypes) {
10✔
2873
                        if (first) {
2✔
2874
                                sig = t;
2✔
2875
                                first = false;
3✔
2876
                        }
2877
                        else {
2878
                                sig += "," + t;
4✔
2879
                        }
2880
                }
1✔
2881
                return sig;
2✔
2882
        }
2883

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

© 2025 Coveralls, Inc