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

moosetechnology / VerveineJ / 19990434677

06 Dec 2025 03:20PM UTC coverage: 50.858% (-0.1%) from 50.975%
19990434677

Pull #178

github

web-flow
Merge 2bae1f45c into 67bcff346
Pull Request #178: Some cleanings

1897 of 3940 branches covered (48.15%)

Branch coverage included in aggregate %.

74 of 86 new or added lines in 2 files covered. (86.05%)

1 existing line in 1 file now uncovered.

4268 of 8182 relevant lines covered (52.16%)

2.1 hits per line

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

75.02
/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
                        TType 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 TType ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
914
                
915
                TType 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 = (TType) 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 TType ensureFamixType(ITypeBinding bnd, TWithTypes context) {
998
                int modifiers = extractModifierOfTypeFrom(bnd);
4✔
999
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1000
        }
1001
        
1002
        public TType ensureFamixType(ITypeBinding bnd) {
1003
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1004
        }
1005

1006
        private int extractModifierOfTypeFrom(ITypeBinding bnd) {
1007
                int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
1008
                return modifiers;
2✔
1009
        }
1010

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

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

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

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

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

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

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

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

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

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

1110
                if (fmx!=null) {
2!
1111
                        // we just created it or it was not bound, so we make sure it has the right information in it
1112
                        if (bnd != null) {
2✔
1113
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1114
                        }
1115
                        TAssociation lastAssoc = null;
2✔
1116

1117
                        if (bnd != null) {
2✔
1118
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1119
                                if (supbnd != null) {
2✔
1120
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1121
                                }
1122
                                else {
1123
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8✔
1124
                                }
1125
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7✔
1126
                        }
1127
                }
1128

1129
                return fmx;
2✔
1130
        }
1131

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

1143
                // --------------- some special cases
1144
                if (bnd != null) {
2✔
1145
                        if (bnd.isArray()) {
3!
1146
                                bnd = bnd.getElementType();
×
1147
                        }
1148

1149
                        // for inner classes defined in generics !!! For others should not change anything
1150
                        bnd = bnd.getErasure();
3✔
1151
                }
1152

1153
                // ---------------- to avoid useless computations if we can
1154
                fmx = (Exception) getEntityByKey(bnd);
5✔
1155
                if (fmx != null) {
2✔
1156
                        return fmx;
2✔
1157
                }
1158

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

1182
                // --------------- owner
1183
                if (owner == null) {
2✔
1184
                        if (bnd == null) {
2✔
1185
                                owner = ensureFamixPackageDefault();
4✔
1186
                        } else {
1187
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1188
                        }
1189
                }
1190

1191
                // --------------- recover from name ?
1192
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13✔
1193
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8!
1194
                                fmx = candidate;
×
1195
                                break;
×
1196
                        }
1197
                }
1✔
1198

1199
                // ---------------- create
1200
                if (fmx == null) {
2!
1201
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7✔
1202
                        fmx.setTypeContainer(owner);
3✔
1203
                }
1204

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

1218
        return fmx;
2✔
1219
        }
1220

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

1230
                // --------------- some special cases
1231
                if (bnd != null) {
2!
1232
                        if (bnd.isArray()) {
3!
1233
                                bnd = bnd.getElementType();
×
1234
                        }
1235

1236
                        // for inner classes defined in generics !!! For others should not change anything
1237
                        bnd = bnd.getErasure();
3✔
1238
                }
1239

1240
                // ---------------- to avoid useless computations if we can
1241
                fmx = (Interface) getEntityByKey(bnd);
5✔
1242
                if (fmx != null) {
2✔
1243
                        return fmx;
2✔
1244
                }
1245

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

1269
                // --------------- owner
1270
                if (owner == null) {
2✔
1271
                        if (bnd == null) {
2!
1272
                                owner = ensureFamixPackageDefault();
×
1273
                        } else {
1274
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1275
                        }
1276
                }
1277

1278
                // --------------- recover from name ?
1279
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13✔
1280
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8✔
1281
                                fmx = candidate;
2✔
1282
                                break;
1✔
1283
                        }
1284
                }
1✔
1285

1286
                // ---------------- create
1287
                if (fmx == null) {
2✔
1288
                        if (isGeneric) {
2✔
1289
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7✔
1290
                        }
1291
                        else {
1292
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7✔
1293
                                fmx.setTypeContainer(owner);
3✔
1294
                        }
1295
                }
1296

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

1310
        public TThrowable asException(TType fmxType) {
1311
                if (fmxType instanceof Exception) {
3✔
1312
                        return (Exception) fmxType;
3✔
1313
                }
1314
                if(fmxType instanceof TypeParameter) {
3✔
1315
                        return (TypeParameter) fmxType;
3✔
1316
                }
1317

1318
                Exception fmxException = null;
2✔
1319
                IBinding key;
1320

1321
                try {
1322
                        key = entityToKey.get(fmxType);
6✔
1323

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

1328
                        TWithTypes owner = fmxType.getTypeContainer();
3✔
1329
                        fmxType.setTypeContainer(null);
3✔
1330
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10✔
1331

1332
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8✔
1333
                        if (fmxType instanceof TWithAttributes) {
3!
1334
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8✔
1335
                        }
1336

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

1352
                return fmxException;
2✔
1353
        }
1354

1355
        /**
1356
         * helper method, we know the type exists, ensureFamixClass will recover it
1357
         */
1358
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1359
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1360
        }
1361

1362
        /**
1363
         * helper method, we know the type exists, ensureFamixInterface will recover it
1364
         */
1365
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1366
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1367
        }
1368

1369
        /**
1370
         * helper method, we know the type exists, ensureFamixInterface will recover it
1371
         */
1372
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1373
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1374
        }
1375

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

1406

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

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

1427
                // --------------- to avoid useless computations if we can
1428
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1429
                if (fmx != null) {
2✔
1430
                        return fmx;
2✔
1431
                }
1432

1433
                // --------------- name
1434
                if (name == null) {
2✔
1435
                        if (bnd == null) {
2!
1436
                                return null;
×
1437
                        }
1438
                        else {
1439
                                name = bnd.getName();
3✔
1440
                        }
1441
                }
1442

1443
                // --------------- owner
1444
                if (owner == null) {
2✔
1445
                        if (bnd == null) {
2!
1446
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1447
                        } else {
1448
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1449
                        }
1450
                }
1451

1452
                // --------------- recover from name ?
1453
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1454
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1455
                                fmx = candidate;
×
1456
                                break;
×
1457
                        }
1458
                }
×
1459

1460
                if (fmx == null) {
2!
1461
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1462
                        fmx.setTypeContainer(owner);
3✔
1463
                }
1464

1465
                if (bnd != null) {
2!
1466
                        setVisibility(fmx, bnd.getModifiers());
5✔
1467
                }
1468

1469
                return fmx;
2✔
1470
        }
1471

1472
        /**
1473
         * helper method, we know the type exists, ensureFamixEnum will recover it
1474
         */
1475
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1476
                return ensureFamixEnum(bnd, name, owner);
6✔
1477
        }
1478

1479
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1480
                EnumValue fmx;
1481

1482
                // --------------- to avoid useless computations if we can
1483
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1484
                if (fmx != null) {
2✔
1485
                        return fmx;
2✔
1486
                }
1487

1488
                // --------------- name
1489
                if (name == null) {
2!
1490
                        if (bnd == null) {
×
1491
                                return null;
×
1492
                        }
1493
                        else {
1494
                                name = bnd.getName();
×
1495
                        }
1496
                }
1497

1498
                // --------------- owner
1499
                if (owner == null) {
2✔
1500
                        if (bnd == null) {
2!
1501
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1502
                        }
1503
                        else {
1504
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1505
                        }
1506
                }
1507

1508
                // --------------- recover from name ?
1509
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
1510
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1511
                                fmx = candidate;
×
1512
                                break;
×
1513
                        }
1514
                }
×
1515
                if (fmx == null) {
2!
1516
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1517
                        fmx.setParentEnum(owner);
3✔
1518
                }
1519

1520
        fmx.setParentEnum(owner);
3✔
1521

1522
        return fmx;
2✔
1523
        }
1524

1525
    /**
1526
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1527
         */
1528
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1529
                AnnotationType fmx;
1530

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

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

1547
                // --------------- owner
1548
                if (owner == null) {
2✔
1549
                        if (bnd == null) {
2!
1550
                                owner = ensureFamixPackageDefault();
×
1551
                        }
1552
                        else {
1553
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1554
                                if (parentPckg != null) {
2!
1555
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1556
                                } else {
1557
                                        owner = this.ensureFamixPackageDefault();
×
1558
                                }
1559
                        }
1560
                }
1561

1562
                // --------------- recover from name ?
1563
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1564
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1565
                                fmx = candidate;
2✔
1566
                                break;
1✔
1567
                        }
1568
                }
1✔
1569

1570
                // --------------- create
1571
                if (fmx == null) {
2✔
1572
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1573
                        fmx.setAnnotationTypesContainer(owner);
3✔
1574
                }
1575

1576
                if (bnd != null) {
2!
1577
                        // Not supported in Famix
1578

1579
                        // setVisibility(fmx, bnd.getModifiers());
1580
                }
1581

1582
                return fmx;
2✔
1583
        }
1584

1585
        /**
1586
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1587
         */
1588
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1589
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1590
        }
1591

1592
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1593
                AnnotationTypeAttribute fmx = null;
2✔
1594

1595
                // --------------- to avoid useless computations if we can
1596
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5✔
1597
                if (fmx != null) {
2✔
1598
                        return fmx;
2✔
1599
                }
1600

1601
                // --------------- name
1602
                if (name == null) {
2!
1603
                        if (bnd == null) {
×
1604
                                return null;
×
1605
                        }
1606
                        else {
1607
                                name = bnd.getName();
×
1608
                        }
1609
                }
1610

1611
                // --------------- owner
1612
                if (owner == null) {
2!
1613
                        if (bnd == null) {
×
1614
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1615
                        }
1616
                        else {
1617
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1618
                                if (parentType != null) {
×
1619
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1620
                                }
1621
                                else  {
1622
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1623
                                }
1624
                        }
1625
                }
1626

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

1642
                if (fmx == null) {
2!
1643
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1644
                        fmx.setParentType(owner);
3✔
1645
                }
1646

1647
                if (bnd != null) {
2!
1648
                        // Not suopp
1649

1650
                        // setVisibility(fmx, bnd.getModifiers());
1651
                }
1652

1653
                return fmx;
2✔
1654
        }
1655

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

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

1695
                // --------------- to avoid useless computations if we can
1696
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1697
                if (fmx != null) {
2✔
1698
                        return fmx;
2✔
1699
                }
1700

1701
                // --------------- name
1702
                if (name == null) {
2✔
1703
                        if (bnd == null) {
2!
1704
                                return null;
×
1705
                        }
1706
                        else {
1707
                                name = bnd.getName();
3✔
1708
                        }
1709
                }
1710

1711
                // --------------- owner
1712
                if (owner == null && bnd != null) {
2!
NEW
1713
            if (bnd.getDeclaringClass() != null) {
×
NEW
1714
                owner = (TWithTypes) this.ensureFamixType(bnd.getDeclaringClass());
×
NEW
1715
            } else if(bnd.getDeclaringMethod() != null) {
×
NEW
1716
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1717
            }
1718
                }
1719

1720
                // --------------- recover from name ?
1721
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1722
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1723
                                fmx = (TypeParameter) candidate;
3✔
1724
                                break;
1✔
1725
                        }
1726
                }
1✔
1727

1728
                // --------------- create
1729
                if (fmx == null) {
2✔
1730
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1731
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1732
                                Type upperBound = (Type)ensureFamixType(bnd.getSuperclass());
6✔
1733
                                fmx.setUpperBound(upperBound);
3✔
1734
                        }
1735
                        if(bnd != null) {
2✔
1736
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17✔
1737
                    Type upperBound = (Type) ensureFamixType(intbnd);
5✔
1738
                    fmx.setUpperBound(upperBound);
3✔
1739
                }
1740
            }
1741
                        fmx.setTypeContainer(owner);
3✔
1742
                }
1743

1744
                return fmx;
2✔
1745
        }
1746

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

1762
                // check whether bnd and candidate are already bound
1763
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1764
                if (res == CheckResult.MATCH) {
3✔
1765
                        return true;
2✔
1766
                } else if (res == CheckResult.FAIL) {
3!
1767
                        return false;
×
1768
                }
1769

1770
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7✔
1771
                        return false;
2✔
1772
                }
1773

1774
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1775
                conditionalMapToKey(bnd, candidate);
4✔
1776
                return true;
2✔
1777
        }
1778

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

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

1803
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
1804
                                bnd = bnd.getElementType();
×
1805
                }
1806

1807
                // checking names
1808
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8!
1809
                        name = bnd.getErasure().getName();
×
1810
                }
1811
                else if (bnd != null) {
2✔
1812
                        name = bnd.getName();
3✔
1813
                }
1814
                // else name = name
1815
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7✔
1816
                        return false;
2✔
1817
                }
1818

1819
                // special case of primitive types
1820
                if (candidate instanceof PrimitiveType) {
3!
1821
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1822
                                // names are equal so it's OK
1823
                                conditionalMapToKey(bnd, candidate);
×
1824
                                return true;
×
1825
                        }
1826
                        else if ( (bnd == null) && (owner == null) ) {
×
1827
                                return true;
×
1828
                        }
1829
                }
1830

1831
                // check owners without bnd
1832
                if (bnd == null) {
2✔
1833
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1834
                }
1835

1836
                // check owners with bnd
1837
                // type is an annotation
1838
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6!
1839
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13!
1840
                                conditionalMapToKey(bnd, candidate);
4✔
1841
                                return true;
2✔
1842
                        } else {
1843
                                return false;
×
1844
                        }
1845
                }
1846

1847
                // check owners with bnd
1848
                // type is a Parameterized type
1849
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6!
1850
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1851
                }
1852

1853
                // check owners with bnd
1854
                // type is an Enum
1855
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3!
1856
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1857
                }
1858

1859
                // check owners with bnd
1860
                // type is something elae (a class or interface)
1861
                // Annotation are interfaces too, so we should check this one after isAnnotation
1862
                if ( bnd.isClass()) {
3!
1863
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1864
                }
1865

1866
                if(bnd.isInterface()) {
3!
1867
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1868
                }
1869

1870
                return false;
2✔
1871
        }
1872

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

1887
                // check whether bnd and candidate are already bound
1888
                CheckResult res = checkKeyMatch(bnd, candidate);
5✔
1889
                if (res == CheckResult.MATCH) {
3!
1890
                        return true;
×
1891
                } else if (res == CheckResult.FAIL) {
3✔
1892
                        return false;
2✔
1893
                }
1894

1895
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1896
                        return false;
×
1897
                }
1898

1899
                // checking owner
1900
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7✔
1901
        }
1902

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

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

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

1929
                // checking owner
1930
                return matchAndMapTypeOwner(bnd, owner, candidate);
6✔
1931
        }
1932

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

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

1958
                // checking names
1959
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10!
1960
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
1961
                        return false;
×
1962
                }
1963

1964
                // for methods, the name is not enough, we must test the signature also
1965
                // but not for AnnotationTypeAttribute
1966

1967
                        if (bnd != null) {
2✔
1968
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7✔
1969
                        }
1970
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6✔
1971
                                return false;
2✔
1972
                        }
1973

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

2008

2009
                // check owner
2010
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13✔
2011
                        conditionalMapToKey(bnd, candidate);
4✔
2012
                        return true;
2✔
2013
                } else {
2014
                        return false;
2✔
2015
                }
2016
        }
2017

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

2033
                // check whether bnd and candidate are already bound
2034
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5✔
2035
                if (keyMatch == CheckResult.MATCH) {
3!
2036
                        return true;
×
2037
                } else if (keyMatch == CheckResult.FAIL) {
3✔
2038
                        return false;
2✔
2039
                }
2040

2041
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2042
                        return false;
×
2043
                }
2044

2045
                // check owner
2046
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2047

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

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

2074
                // check owner
2075
                // "normal" field?
2076
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2077
                if (res == CheckResult.MATCH) {
3!
2078
                        conditionalMapToKey(bnd, candidate);
4✔
2079
                        return true;
2✔
2080
                }
2081
                return false;
×
2082
        }
2083

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

2095
                // owner is a Method? (for example in case of an anonymous class)
2096
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2097
                if (res == CheckResult.MATCH) {
3!
2098
                        conditionalMapToKey(bnd, candidate);
×
2099
                        return true;
×
2100
                } else if (res == CheckResult.FAIL) {
3!
2101
                        return false;
×
2102
                }
2103

2104
                // owner is a class ?
2105
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2106
                if (res == CheckResult.MATCH) {
3✔
2107
                        conditionalMapToKey(bnd, candidate);
4✔
2108
                        return true;
2✔
2109
                }
2110
                else if (res == CheckResult.FAIL) {
3✔
2111
                        return false;
2✔
2112
                }
2113

2114
                // owner must be a package
2115
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2116
                        conditionalMapToKey(bnd, candidate);
4✔
2117
                        return true;
2✔
2118
                }
2119
                return false;
2✔
2120
        }
2121

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

2135
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2136
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2137
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2138

2139
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
2140
                                return CheckResult.MATCH;
×
2141
                        } else {
2142
                                return CheckResult.FAIL;
2✔
2143
                        }
2144
                }
2145
                return CheckResult.UNDECIDED;
2✔
2146
        }
2147

2148
        /**
2149
         * @param typBnd
2150
         * @param owner
2151
         * @param candidateOwner
2152
         * @return a {@link CheckResult}
2153
         */
2154
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2155
                if ((typBnd != null) || (owner instanceof Type)) {
5✔
2156
                        if (!(candidateOwner instanceof Type)) {
3✔
2157
                                return CheckResult.FAIL;
2✔
2158
                        }
2159

2160
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2161
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2162

2163
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2164
                                return CheckResult.MATCH;
2✔
2165
                        } else {
2166
                                return CheckResult.FAIL;
2✔
2167
                        }
2168
                }
2169
                return CheckResult.UNDECIDED;
2✔
2170
        }
2171

2172
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2173
                if ((pckgBnd != null) || (owner instanceof Package)) {
5!
2174
                        if (!(candidateOwner instanceof Package)) {
3!
2175
                                return CheckResult.FAIL;
×
2176
                        }
2177

2178
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2179
                        String ownerName = (owner != null) ? owner.getName() : null;
6!
2180

2181
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2182
                                return CheckResult.MATCH;
2✔
2183
                        } else {
2184
                                return CheckResult.FAIL;
2✔
2185
                        }
2186
                }
2187
                return CheckResult.UNDECIDED;
×
2188
        }
2189

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

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

2221
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2222
                if (bound == candidate) {
3✔
2223
                        return CheckResult.MATCH;
2✔
2224
                }
2225
                else if (bound != null) {
2✔
2226
                        return CheckResult.FAIL;
2✔
2227
                }
2228
                else if (getEntityKey(candidate) != null) {
4✔
2229
                        // candidate already bound, and not to this binding
2230
                        return CheckResult.FAIL;
2✔
2231
                }
2232
                else {
2233
                        return CheckResult.UNDECIDED;
2✔
2234
                }
2235
        }
2236

2237
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2238
                if (bnd != null) {
2✔
2239
                        mapEntityToKey(bnd, ent);
4✔
2240
                }
2241
        }
1✔
2242

2243
        public Method ensureFamixMethod(IMethodBinding bnd) {
2244
                return ensureFamixMethod(
8✔
2245
                                bnd,
2246
                                /*name*/null,
2247
                                /*paramsType*/null,
2248
                                /*returnType*/null,
2249
                                /*owner*/null,
2250
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2251
        }
2252

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

2266
                // --------------- to avoid useless computations if we can
2267
                fmx = (Method)getEntityByKey(bnd);
5✔
2268
                if (fmx != null) {
2✔
2269
                        return fmx;
2✔
2270
                }
2271

2272
                // --------------- name
2273
                if (name == null) {
2✔
2274
                        if (bnd == null) {
2✔
2275
                                return null;
2✔
2276
                        }
2277
                        else {
2278
                                name = bnd.getName();
3✔
2279
                        }
2280
                }
2281

2282
                // --------------- signature
2283
                sig = name + "(";
3✔
2284
                 if (bnd != null) {
2✔
2285
                    sig += signatureParamsFromBinding(bnd);
7✔
2286
                }
2287
        else if (paramTypes != null) {
2!
2288
                        sig += signatureParamsFromStringCollection(paramTypes);
7✔
2289
                }
2290
                else {
2291
                        sig += "???";
×
2292
                }
2293
                sig += ")";
3✔
2294

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

2311
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2312
                    delayedRetTyp = true;
3✔
2313
                }
2314
                else {
2315
                    ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2316
                }
2317
                        }
2318
                }
2319

2320
                // --------------- owner
2321
                if (owner == null) {
2✔
2322
                        if (bnd == null) {
2✔
2323
                                owner = ensureFamixClassStubOwner();
4✔
2324
                        }
2325
                        else {
2326
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2327
                                if (classBnd != null) {
2!
2328
                                        TType tmpOwn = ensureFamixType(classBnd);
4✔
2329

2330
                                        owner = (TWithMethods) tmpOwn;
3✔
2331
                                        
2332
                                }
1✔
2333
                                else {
2334
                                        owner = ensureFamixClassStubOwner();
×
2335
                                }
2336
                        }
2337
                }
2338

2339
                // --------------- recover from name ?
2340
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13✔
2341
                        if (matchAndMapMethod(bnd, sig, ret, (TNamedEntity) owner, candidate)) {
9✔
2342
                                fmx = candidate;
2✔
2343
                                break;
1✔
2344
                        }
2345
                }
1✔
2346

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

2367
        setMethodModifiers(fmx, modifiers);
4✔
2368
        // if it's a constructor
2369
        if (fmx.getName().equals(Util.getOwner(fmx).getName())) {
7✔
2370
            fmx.setKind(CONSTRUCTOR_KIND_MARKER);
3✔
2371
        }
2372

2373
        //If it has the #default keywork, we mark it as default implementation
2374
        if (Modifier.isDefault(modifiers)) {
3✔
2375
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3✔
2376
        }
2377

2378
        if (delayedRetTyp) {
2✔
2379
                        int retTypModifiers = retTypBnd.getModifiers();
3✔
2380
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3✔
2381
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2382
                }
2383

2384
                return fmx;
2✔
2385
        }
2386

2387
        /**
2388
         * Creates or recovers a stub Famix Method
2389
         * @param name of the method
2390
         * @return the Famix Method
2391
         */
2392
        public Method ensureFamixStubMethod(String name) {
NEW
2393
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2394
        }
2395

2396
        public void setAttributeModifiers(Attribute fmx, int mod) {
2397
                setCommonModifiers(fmx, mod);
4✔
2398
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2399
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2400
        }
1✔
2401

2402
        public void setMethodModifiers(Method fmx, int mod) {
2403
                setCommonModifiers(fmx, mod);
4✔
2404
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2405
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2406
        }
1✔
2407

2408
        public void setClassModifiers(Class fmx, int mod) {
2409
                setCommonModifiers(fmx, mod);
4✔
2410
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2411
        }
1✔
2412

2413
        public void setInterfaceModifiers(Interface fmx, int mod) {
2414
                setCommonModifiers(fmx, mod);
4✔
2415
        }
1✔
2416

2417
        private void setCommonModifiers(Entity fmx, int mod) {
2418
                setVisibility((THasVisibility)fmx, mod);
5✔
2419
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2420
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2421
        }
1✔
2422

2423
        /**
2424
         * Sets the visibility of a FamixNamedEntity
2425
         *
2426
         * @param fmx -- the FamixNamedEntity
2427
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2428
         */
2429
        public void setVisibility(THasVisibility fmx, int mod) {
2430
                if (Modifier.isPublic(mod)) {
3✔
2431
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2432
                } else if (Modifier.isPrivate(mod)) {
3✔
2433
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2434
                } else if (Modifier.isProtected(mod)) {
3✔
2435
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2436
                } else {
2437
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2438
                }
2439
        }
1✔
2440

2441
        /**
2442
         * Returns a Famix Attribute associated with the IVariableBinding.
2443
         * The Entity is created if it does not exist.<br>
2444
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2445
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2446
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2447
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2448
         */
2449
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2450
                Attribute fmx;
2451

2452
                // --------------- to avoid useless computations if we can
2453
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2454
                if (fmx != null) {
2✔
2455
                        return fmx;
2✔
2456
                }
2457

2458
                // --------------- name
2459
                if (name == null) {
2!
2460
                        if (bnd == null) {
×
2461
                                return null;
×
2462
                        }
2463
                        else {
2464
                                name = bnd.getName();
×
2465
                        }
2466
                }
2467

2468
                // --------------- owner
2469
                if (owner == null) {
2✔
2470
                        if (bnd == null) {
2!
2471
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2472
                        }
2473
                        else {
2474
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2475
                                        // Declaring class is the generic one if the class is parametric.
2476
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2477
                                } else {
2478
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2479
                                }
2480
                        }
2481
                }
2482

2483
                // --------------- recover from name ?
2484
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2485
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2486
                                fmx = candidate;
2✔
2487
                                break;
1✔
2488
                        }
2489
                }
1✔
2490

2491
                if (fmx == null) {
2✔
2492
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2493
                        fmx.setParentType( owner);
3✔
2494
                }
2495

2496
        fmx.setParentType(owner);
3✔
2497
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2498
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2499
        if (bnd != null) {
2✔
2500
            int mod = bnd.getModifiers();
3✔
2501
            setAttributeModifiers(fmx, mod);
4✔
2502
        }
2503

2504
        return fmx;
2✔
2505
        }
2506

2507
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2508
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2509
        }
2510

2511
        /**
2512
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2513
         */
2514
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2515
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2516
        }
2517

2518
        /**
2519
         * Returns a Famix Parameter associated with the IVariableBinding.
2520
         * The Entity is created if it does not exist.<br>
2521
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2522
         */
2523
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2524
                Parameter fmx = null;
2✔
2525

2526
                // --------------- to avoid useless computations if we can
2527
                try {
2528
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2529
                }catch(Throwable e) {
×
2530
                        e.printStackTrace();
×
2531
                }
1✔
2532
                if (fmx != null) {
2✔
2533
                        return fmx;
2✔
2534
                }
2535

2536
                // --------------- name
2537
                if (name == null) {
2!
2538
                        if (bnd == null) {
×
2539
                                return null;
×
2540
                        }
2541
                        else {
2542
                                name = bnd.getName();
×
2543
                        }
2544
                }
2545

2546
                // --------------- owner
2547
                if (tMethod == null) {
2!
2548
                        if (bnd == null) {
×
2549
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2550
                        }
2551
                        else {
2552
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2553
                        }
2554
                }
2555

2556
                // --------------- recover from name ?
2557
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2558
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
2559
                                fmx = candidate;
×
2560
                                break;
×
2561
                        }
2562
                }
1✔
2563

2564
                if (fmx == null) {
2!
2565
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2566
                }
2567

2568
                if (fmx != null) {
2!
2569
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2570
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2571
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2572
                }
2573

2574
                return fmx;
2✔
2575
        }
2576

2577
    /**
2578
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2579
         * The Entity is created if it does not exist.<br>
2580
         * @param name -- the name of the FAMIX LocalVariable
2581
         * @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
2582
         */
2583
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2584
                LocalVariable fmx;
2585

2586
                // --------------- to avoid useless computations if we can
2587
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2588
                if (fmx != null) {
2!
2589
                        return fmx;
×
2590
                }
2591

2592
                // --------------- name
2593
                if (name == null) {
2!
2594
                        if (bnd == null) {
×
2595
                                return null;
×
2596
                        }
2597
                        else {
2598
                                name = bnd.getName();
×
2599
                        }
2600
                }
2601

2602
                // --------------- owner
2603
                if (owner == null) {
2!
2604
                        if (bnd == null) {
×
2605
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2606
                        }
2607
                        else {
2608
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2609
                        }
2610
                }
2611

2612
                // --------------- recover from name ?
2613
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2614
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
2615
                                fmx = candidate;
×
2616
                                break;
×
2617
                        }
2618
                }
1✔
2619

2620
                if (fmx == null) {
2!
2621
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2622
                        fmx.setParentBehaviouralEntity(owner);
3✔
2623
                }
2624

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

2628
        return fmx;
2✔
2629
        }
2630

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

2646
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2647
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2648
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2649
        }
2650

2651
        /**
2652
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2653
         * @param jCmt -- the content (String) of the comment 
2654
         * @param owner -- the entity that is commented
2655
         * @return the Famix Comment
2656
         */
2657
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2658
                Comment cmt = null;
2✔
2659

2660
                if ( (jCmt != null) && (owner != null) ) {
4!
2661
                        
2662
                        cmt = new Comment();
4✔
2663
                        addSourceAnchor(cmt, jCmt);
5✔
2664
                        famixRepoAdd(cmt);
3✔
2665
                        cmt.setCommentedEntity(owner);
3✔
2666
                }
2667

2668
                return cmt;
2✔
2669
        }
2670

2671
        /**
2672
         * Creates and returns a Famix Comment and associates it with an Entity
2673
         * @param jCmt -- the content (String) of the comment 
2674
         * @param owner -- the entity that is commented
2675
         * @param content -- the text of the comment
2676
         * @return the Famix Comment
2677
         */
2678
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2679
                Comment cmt = null;
2✔
2680

2681
                if ( (jCmt != null) && (owner != null) ) {
4!
2682
                        cmt = new Comment();
4✔
2683
                        cmt.setContent(content );
3✔
2684
                        famixRepoAdd(cmt);
3✔
2685
                        cmt.setCommentedEntity(owner);
3✔
2686
                }
2687

2688
                return cmt;
2✔
2689
        }
2690

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

2702
                fa = createIndexedFileAnchor(node);
4✔
2703
                if ((fmx != null) && (fa != null)) {
4!
2704
                        fmx.setSourceAnchor(fa);
3✔
2705
                        famixRepoAdd(fa);
3✔
2706
                }
2707

2708
                return fa;
2✔
2709
        }
2710

2711
        /**
2712
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2713
         */
2714
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2715
                IndexedFileAnchor fa;
2716

2717
                fa = createIndexedFileAnchor(node);
4✔
2718
                if ((fmx != null) && (fa != null)) {
4!
2719

2720
                        // may change the positions
2721
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2722
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2723
                        if (node.getName() != null) {
3!
2724
                                methodDeclarationModifiers.add(node.getName());
5✔
2725
                        }
2726
                        if (node.getReturnType2() != null) {
3✔
2727
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2728
                        }
2729
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2730
                        int end = node.getStartPosition() + node.getLength();
6✔
2731

2732
                        fa.setStartPos(beg);
4✔
2733
                        fa.setEndPos(end);
4✔
2734

2735
                        fmx.setSourceAnchor(fa);
3✔
2736
                        famixRepoAdd(fa);
3✔
2737
                }
2738

2739
                return fa;
2✔
2740
        }
2741

2742
        /**
2743
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2744
         * Information returned in the form of an IndexedFileAnchor
2745
         */
2746
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2747
                IndexedFileAnchor fa;
2748
                
2749
                if (node == null) {
2!
2750
                        return null;
×
2751
                }
2752

2753
                // position in source file
2754
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2755
                int end = beg + node.getLength() - 1;
7✔
2756

2757
                // find source Compilation Unit
2758
                // there is a special case for the JDT Comment Nodes
2759
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2760
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2761
                } else {
2762
                        node = node.getRoot();
3✔
2763
                }
2764

2765
                fa = new IndexedFileAnchor();
4✔
2766
                fa.setStartPos(beg);
4✔
2767
                fa.setEndPos(end);
4✔
2768

2769
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6✔
2770

2771
                return fa;
2✔
2772
        }
2773

2774
        /**
2775
         * Creates or recovers the Famix Class for "Object".
2776
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2777
         *
2778
         * @return a Famix class for "Object"
2779
         */
2780
        public Class ensureFamixClassObject() {
2781
        // 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...
2782
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5✔
2783

2784
        for (Class entity : objects) {
10✔
2785
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2786
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7✔
2787
                    return entity;
2✔
2788
                }
2789
        }
1✔
2790

2791
        Class fmx = createFamixEntity(Class.class, "Object");
6✔
2792
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2793
                return fmx;
2✔
2794
        }
2795

2796
        /**
2797
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2798
         */
2799
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2800
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2801
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2802

2803
                if (fmx != null) {
2!
2804
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2805
                }
2806

2807
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
NEW
2808
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
2809
                }
2810

2811
                return fmx;
2✔
2812
        }
2813

2814
        public Class getFamixMetaClass(ITypeBinding bnd) {
2815
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2816
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2817
        }
2818

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

2832
                        // may be not needed anymore now that we use modifiers
2833
                        /*fmx.setIsAbstract(Boolean.FALSE);
2834
                        fmx.setIsFinal(Boolean.FALSE);
2835
                        fmx.setIsInterface(Boolean.FALSE); 
2836
                        fmx.setIsPrivate(Boolean.FALSE);
2837
                        fmx.setIsProtected(Boolean.FALSE);*/
2838
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2839
                }
2840

2841
                return fmx;
×
2842
        }
2843

2844
        public String removeLastPartOfPackageName(String qualifiedName) {
2845
                String ret;
2846
                int last = qualifiedName.lastIndexOf('.');
4✔
2847
                if (last > 0) {
2✔
2848
                        // recursively creating the parent
2849
                        ret = qualifiedName.substring(0, last);
6✔
2850
                }
2851
                else {
2852
                        ret = "";
2✔
2853
                }
2854

2855
                return ret;
2✔
2856
        }
2857

2858
        /** Generates the list of parameters for a method signature
2859
         * @return a string
2860
         */
2861
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2862
                boolean first = true;
2✔
2863
                String sig = "";
2✔
2864

2865
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2866
                        if (first) {
2✔
2867
                                sig = parBnd.getName();
3✔
2868
                                first = false;
3✔
2869
                        }
2870
                        else {
2871
                                sig += "," + parBnd.getName();
5✔
2872
                        }
2873
                }
2874
                return sig;
2✔
2875
        }
2876

2877
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2878
                boolean first = true;
2✔
2879
                String sig = "";
2✔
2880

2881
                for (String t : paramTypes) {
10✔
2882
                        if (first) {
2✔
2883
                                sig = t;
2✔
2884
                                first = false;
3✔
2885
                        }
2886
                        else {
2887
                                sig += "," + t;
4✔
2888
                        }
2889
                }
1✔
2890
                return sig;
2✔
2891
        }
2892

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