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

moosetechnology / VerveineJ / 37473201091

06 Oct 2026 01:44PM UTC coverage: 52.92% (-0.06%) from 52.984%
37473201091

Pull #275

github

web-flow
Merge f0a4eb6c8 into 7953741d5
Pull Request #275: Setup mooseci on every PR

2037 of 4020 branches covered (50.67%)

Branch coverage included in aggregate %.

4515 of 8361 relevant lines covered (54.0%)

2.22 hits per line

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

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

3
import java.util.*;
4

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

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

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

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

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

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

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

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

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

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

113
        /**
114
         * Another dictionary to map a name to FAMIX Entities with this name
115
         */
116
        protected Map<String,Collection<TNamedEntity>> nameToEntity;
117
        
118
        /**
119
         * Yet another dictionary for implicit variables ('self' and 'super')
120
         * Because they are implicit, they may not have a binding provided by the parser,
121
         * or may have the same binding as their associated type so they can't be kept easily in {@link #keyToEntity}
122
         */
123
        @Deprecated
124
        protected Map<Type,ImplicitVars> typeToImpVar;
125

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

143
        /**
144
         * Option: If true, create stubs without package into a "Missing" package
145
         */
146
        protected boolean useMissingPackage;
147

148
        /** Constructor taking a FAMIX repository
149
         * @param famixRepo
150
         */
151
        public EntityDictionary(Repository famixRepo) {
2 ✔
152
                        this.famixRepo = famixRepo;
3 ✔
153
                        
154
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5 ✔
155
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5 ✔
156
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5 ✔
157
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5 ✔
158
                        
159
                        if (! this.famixRepo.isEmpty()) {
4 ✔
160
                                recoverExistingRepository();
2 ✔
161
                        }
162
                }
1 ✔
163
        
164
        /** Constructor taking a FAMIX repository and the useMissingPackage option
165
         * @param famixRepo
166
         * @param useMissingPackage
167
         */
168
        public EntityDictionary(Repository famixRepo, boolean useMissingPackage) {
2 ✔
169
                        this.famixRepo = famixRepo;
3 ✔
170
                        this.useMissingPackage = useMissingPackage;
3 ✔
171
                        
172
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5 ✔
173
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5 ✔
174
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5 ✔
175
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5 ✔
176
                        
177
                        if (! this.famixRepo.isEmpty()) {
4 ✔
178
                                recoverExistingRepository();
2 ✔
179
                        }
180
                }
1 ✔
181

182
    /**
183
         * Resets the dictionnary in a proper state after loading entities from an existing MSE file:
184
         * <UL>
185
         * <li>map all named entities to their names in <b>mapName</b></li>
186
         * <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>
187
         * </ul>
188
         */
189
        protected void recoverExistingRepository() {
190
                for (NamedEntity ent : famixRepo.all(NamedEntity.class)) {
13 ✔
191
                        try {
192
                                mapEntityToName(ent.getName(), ent);
5 ✔
193
                        } catch (java.lang.Exception e) {
×
194
                                System.err.println("Error recovering entity " + ent.getName() + " from repository " + famixRepo);
×
195
                        };
1 ✔
196
                        // for the Exception to be raised, the return value must be tested
197
                        try { if (((TCanBeStub) ent).getIsStub()) {} }
5 ✔
198
                        catch (NullPointerException e) { ((TCanBeStub)ent).setIsStub(Boolean.FALSE); }
6 ✔
199
                }
1 ✔
200

201
                for (Access acc : famixRepo.all(Access.class)) {
13 ✔
202
                        // for the Exception to be raised, the return value must be tested
203
                        try { if (acc.getIsWrite()) {}        }
4 ✔
204
                        catch (NullPointerException e) { acc.setIsWrite(Boolean.FALSE); }
5 ✔
205
                }
1 ✔
206
        }
1 ✔
207

208
        protected void mapEntityToName(String name, TNamedEntity ent) {
209
                
210
                Collection<TNamedEntity> l_ent = nameToEntity.get(name);
6 ✔
211
                if (l_ent == null) {
2 ✔
212
                        l_ent = new LinkedList<>();
4 ✔
213
                }
214
                l_ent.add(ent);
4 ✔
215
                nameToEntity.put(name, l_ent);
6 ✔
216
        }
1 ✔
217

218
        public void removeEntity( NamedEntity ent) {
219
                IBinding key;
220
                key = entityToKey.get(ent);
6 ✔
221
                if (key != null) {
2 ✔
222
                        entityToKey.remove(ent);
5 ✔
223
                        keyToEntity.remove(key);
5 ✔
224
                }
225

226
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7 ✔
227
                if (l_ent != null) {
2 ✔
228
                        l_ent.remove(ent);
4 ✔
229
                }
230

231
                famixRepo.getElements().remove(ent);
6 ✔
232
        }
1 ✔
233
        
234
        protected void mapEntityToKey(IBinding key, TNamedEntity ent) {
235
                TNamedEntity old = keyToEntity.get(key);
6 ✔
236
                if (old != null) {
2 ✔
237
                        entityToKey.remove(old);
5 ✔
238
                }
239
                keyToEntity.put(key, ent);
6 ✔
240
                entityToKey.put(ent, key);
6 ✔
241
        }
1 ✔
242
        
243
        /**
244
         * Returns all the Famix Entity with the given name and class 
245
         * @param fmxClass -- the subtype of Famix Entity we are looking for
246
         * @param name -- the name of the entity
247
         * @return the Collection of Famix Entities with the given name and class (possibly empty)
248
         */
249
        @SuppressWarnings("unchecked")
250
        public <T extends TNamedEntity> Collection<T> getEntityByName(java.lang.Class<T> fmxClass, String name) {
251
                Collection<T> ret = new LinkedList<T>();
4 ✔
252
                Collection<TNamedEntity> l_name = nameToEntity.get(name);
6 ✔
253
                
254
                if (l_name != null ) {
2 ✔
255
                        for (TNamedEntity obj : l_name) {
10 ✔
256
                                if (fmxClass.isInstance(obj)) {
4 ✔
257
                                        ret.add((T) obj);
4 ✔
258
                                }
259
                        }
1 ✔
260
                }
261

262
                return ret;
2 ✔
263
        }
264

265
        /**
266
         * Returns the Famix Entity associated to the given key.
267
         * <b>Note</b>: Be careful that ImplicitVariables share the same binding as their associated Class and cannot be retrieved with this method.
268
         * In such a case, this method will always retrieve the Class associated to the key.
269
         * To get an ImplicitVariable from the key, use {@link #getImplicitVariableByBinding(IBinding, String)}
270
         * @param key -- the key
271
         * @return the Famix Entity associated to the binding or null if not found
272
         */
273
        public TNamedEntity getEntityByKey(IBinding key) {
274
                if (key == null) {
2 ✔
275
                        return null;
2 ✔
276
                }
277
                else {
278
                        return keyToEntity.get(key);
6 ✔
279
                }
280
        }
281

282
        /**
283
         * Returns the Famix Entity associated to the given key if it is an instance of the given Famix class.
284
         * This avoids recovering a binding as another kind of entity than the one requested.
285
         * @param key -- the key
286
         * @param fmxClass -- the expected Famix class
287
         * @return the Famix Entity associated to the binding or null if not found or not an instance of <b>fmxClass</b>
288
         */
289
        protected <T extends TNamedEntity> T getEntityByKey(IBinding key, java.lang.Class<T> fmxClass) {
290
                TNamedEntity fmx = getEntityByKey(key);
4 ✔
291
                if (fmxClass.isInstance(fmx)) {
4 ✔
292
                        return fmxClass.cast(fmx);
5 ✔
293
                }
294
                return null;
2 ✔
295
        }
296

297
        /**
298
         * Returns the key associated to a Famix Entity.
299
         * @param e -- the Named entity
300
         * @return the key associated to this entity or null if none
301
         */
302
        public IBinding getEntityKey(TNamedEntity e) {
303
                return entityToKey.get(e);
6 ✔
304
        }
305

306
        /**
307
         * Creates and returns a FAMIX Entity of the type <b>fmxjava.lang.Class</b>.
308
         * The Entity is always created.
309
         * @param fmxClass -- the FAMIX class of the instance to create
310
         * @param name -- the name of the new instance must not be null (and this is not tested)
311
         * @return the FAMIX Entity or null in case of a FAMIX error
312
         */
313
        protected <T extends TNamedEntity & TSourceEntity> T createFamixEntity(java.lang.Class<T> fmxClass, String name) {
314
                T fmx = null;
2 ✔
315

316
                if (name == null) {
2 !
317
                        return null;
×
318
                }
319
                
320
                try {
321
                        fmx = fmxClass.getDeclaredConstructor().newInstance();
9 ✔
322
                } catch (java.lang.Exception e) {
×
323
                        System.err.println("Unexpected error, could not create a FAMIX entity: "+e.getMessage());
×
324
                        e.printStackTrace();
×
325
                }
1 ✔
326
                
327
                if (fmx != null) {
2 !
328
                        fmx.setName(name);
3 ✔
329
                        if (fmx instanceof TCanBeStub) {
3 !
330
                                ((TCanBeStub)fmx).setIsStub(Boolean.TRUE);
4 ✔
331
                        }
332

333
                        mapEntityToName(name, fmx);
4 ✔
334
                        
335
                        // put new entity in Famix repository
336
                        famixRepoAdd((Entity) fmx);
4 ✔
337
                }
338

339
                return fmx;
2 ✔
340
        }
341
        
342
        /**
343
         * Returns a Famix Entity of the type <b>fmxjava.lang.Class</b> and maps it to its binding <b>bnd</b> (if not null).
344
         * The Entity is created if it did not exist.
345
         * @param fmxClass -- the Famix class of the instance to create
346
         * @param bnd -- the binding to map to the new instance
347
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
348
         * @return the Famix Entity or null if <b>bnd</b> was null or in case of a Famix error
349
         */
350
        @SuppressWarnings("unchecked")
351
        protected <T extends TNamedEntity & TSourceEntity> T ensureFamixEntity(java.lang.Class<T> fmxClass, IBinding bnd, String name) {
352
                T fmx = null;
2 ✔
353
                
354
                /* 
355
                 * Unfortunately different entities with the same name and same type may exist
356
                 * e.g. 2 parameters of 2 different methods but having the same name
357
                 * so we cannot recover just from the name
358
                 */
359

360
                if (bnd != null) {
2 ✔
361
                        fmx = getEntityByKey(bnd, fmxClass);
5 ✔
362
                        if (fmx != null) {
2 ✔
363
                                return fmx;
2 ✔
364
                        }
365
                }
366

367
                // else
368
                fmx = createFamixEntity(fmxClass, name);
5 ✔
369
                if ( (bnd != null) && (fmx != null) ) {
4 !
370
                        mapEntityToKey(bnd, fmx);
4 ✔
371
                }
372
                
373
                return fmx;
2 ✔
374
        }
375

376
        /**
377
         * Adds an already created Entity to the Famix repository
378
         * Used mainly for non-NamedEntity, for example relationships
379
         * @param e -- the Famix entity to add to the repository
380
         */
381
        public void famixRepoAdd(Entity e) {
382
                this.famixRepo.add(e);
4 ✔
383
        }
1 ✔
384

385

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

409
        /**
410
         * Returns a Famix ParametricInterface with the given <b>name</b>, creating it if it does not exist yet
411
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
412
         * @param name -- the name of the Famix Class
413
         * @return the Famix Class or null in case of a Famix error
414
         */
415
        public ParametricInterface ensureFamixParametricInterface(ITypeBinding key, String name, TWithTypes owner) {
416
                ParametricInterface fmx = ensureFamixEntity(ParametricInterface.class, key, name);
7 ✔
417
                if(key != null) {
2 !
418
                        for (ITypeBinding tp : key.getTypeParameters()) {
17 ✔
419
                                // If there is a type parameter, then fmx will be a Famix ParametricInterface
420
                                // note: in Famix, the owner of the TypeParameter is the ParametricInterface
421
                                TypeParameter fmxParam = ensureFamixTypeParameter(tp,
5 ✔
422
                                                tp.getName(), fmx);
2 ✔
423
                                fmxParam.setGenericEntity(fmx);
3 ✔
424
                fmxParam.setIsStub(false);
4 ✔
425
            }
426
                }
427
                fmx.setTypeContainer(owner);
3 ✔
428
                return fmx;
2 ✔
429
        }
430

431
        public AnnotationInstanceAttribute createFamixAnnotationInstanceAttribute(AnnotationTypeAttribute att, String value) {
432
                AnnotationInstanceAttribute fmx = null;
2 ✔
433
                if ( (att != null) && (value != null) ) {
4 !
434
                        fmx = new AnnotationInstanceAttribute();
4 ✔
435
                        fmx.setAnnotationTypeAttribute(att);
3 ✔
436
                        fmx.setValue(value);
3 ✔
437
                        this.famixRepo.add(fmx);
4 ✔
438
                }
439
                return fmx;
2 ✔
440
        }
441

442
        public AnnotationInstance addFamixAnnotationInstance(TWithAnnotationInstances fmx, AnnotationType annType, Collection<AnnotationInstanceAttribute> annAtts) {
443
                AnnotationInstance inst = null;
2 ✔
444
                if ( (fmx != null) && (annType != null) ) {
4 !
445
                        inst = new AnnotationInstance();
4 ✔
446
                        inst.setAnnotatedEntity(fmx);
3 ✔
447
                        inst.setAnnotationType(annType);
3 ✔
448
                        inst.addAttributes(annAtts);
3 ✔
449
                        this.famixRepo.add(inst);
4 ✔
450
                }
451
                return inst;
2 ✔
452
        }
453

454
        ///// ensure Famix Relationships /////
455

456
        /**
457
         * Returns a Famix Inheritance relationship between two Famix Classes creating it if needed
458
         * @param sup -- the super class
459
         * @param sub -- the sub class
460
         * @param prev -- previous inheritance relationship in the same context
461
         * @return the Inheritance relationship
462
         */
463
        public Inheritance ensureFamixInheritance(TWithInheritances sup, TWithInheritances sub, TAssociation prev, ITypeBinding supBnd) {
464
                if ( (sup == null) || (sub == null) ) {
4 !
465
                        return null;
×
466
                }
467

468
                // Does the inheritance already exist?
469
                for (TInheritance i : (sup).getSubInheritances()) {                        
11 ✔
470
                        if (i.getSubclass() == sub) {
4 ✔
471
                                return (Inheritance) i;
3 ✔
472
                        }
473
                }
1 ✔
474

475
                Inheritance inh;
476
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 ✔
477
                        inh = (ParametricInheritance)buildFamixParametricAssociation(new ParametricInheritance(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13 ✔
478
                } else {
479
                        inh = new Inheritance();
4 ✔
480
                }
481

482
                inh.setSuperclass(sup);
3 ✔
483
                inh.setSubclass(sub);
3 ✔
484
                chainPrevNext(prev, inh);
4 ✔
485
                famixRepoAdd(inh);
3 ✔
486
                return inh;
2 ✔
487
        }
488
        
489
        /**
490
         * Creates the concretization between the type parameters of the generic entity that is target of an association 
491
         * and the concrete types that concretize them in this association.
492
         * @param association -- the association that must be linked to # or several concretizations
493
         * @param typeParameters -- the collection of type parameters declared in the generic entity
494
         * @param typeArguments -- the collection of concrete types linked to this association
495
         * @return the parametric association
496
         */
497
        public  <T extends TParametricEntity> TParametricAssociation buildFamixParametricAssociation(TParametricAssociation association, ITypeBinding[] typeParameters, ITypeBinding[] typeArguments
498
        ) {
499
                
500
                Iterator<ITypeBinding> genericIterator = Arrays.asList(typeParameters).iterator();
4 ✔
501
                Iterator<ITypeBinding> concreteIterator = Arrays.asList(typeArguments).iterator();
4 ✔
502

503
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6 ✔
504
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7 ✔
505
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7 ✔
506

507
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
508
                        association.addConcretization(concretization);
3 ✔
509
                }
1 ✔
510

511
                return association;
2 ✔
512
        }
513

514
        /**
515
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
516
         * @param typeArgument -- the concrete type
517
         * @param typeParameter -- the generic type parameter
518
         * @return the Concretization relationship
519
         */
520
        public Concretization ensureFamixConcretization(TTypeArgument typeArgument, TypeParameter typeParameter ) {
521
                if ( (typeArgument == null) || (typeParameter == null) ) {
4 !
522
                        return null;
×
523
                }
524

525
                Concretization concretization = new Concretization();
4 ✔
526
                concretization.setTypeArgument(typeArgument);
3 ✔
527
                concretization.setTypeParameter(typeParameter);
3 ✔
528

529
                famixRepoAdd(concretization);
3 ✔
530
                return concretization;
2 ✔
531
        }
532
        
533
                /**
534
         * Returns a Famix Implementation relationship between two Famix Classes creating it if needed
535
         * @param myInterface -- the implemented interface
536
         * @param implementingClass -- the implementing class
537
         * @param prev -- previous inheritance relationship in the same context
538
         * @return the Inheritance relationship
539
         */
540
        public Implementation ensureFamixImplementation(TImplementable myInterface, TCanImplement implementingClass, TAssociation prev, ITypeBinding supBnd) {
541
                if ( (myInterface == null) || (implementingClass == null) ) {
4 !
542
                        return null;
×
543
                }
544

545
                for (TImplementation imp : myInterface.getImplementations()) {
11 ✔
546
                        if (imp.getImplementingClass() == implementingClass) {
4 ✔
547
                                return (Implementation) imp;
3 ✔
548
                        }
549
                }
1 ✔
550
                
551
                Implementation implementation;
552
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 !
553
                        implementation = (ParametricImplementation)buildFamixParametricAssociation(new ParametricImplementation(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13 ✔
554
                } else {
555
                        implementation = new Implementation();
4 ✔
556
                }
557

558
                implementation.setImplementingClass(implementingClass);
3 ✔
559
                implementation.setMyInterface(myInterface);
3 ✔
560
                chainPrevNext(prev, implementation);
4 ✔
561
                famixRepoAdd(implementation);
3 ✔
562
                return implementation;
2 ✔
563
        }
564

565
        public void ensureImplementedInterfaces(ITypeBinding bnd, TType fmx, TWithTypes owner, TAssociation lastAssociation) {
566
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17 ✔
567
                        Type superTyp;
568
                        if(intbnd.isClass()){
3 ✔
569
                                superTyp = this.ensureFamixInterface(intbnd, intbnd.getName(), null, intbnd.isGenericType() || intbnd.isParameterizedType() || intbnd.isRawType(), intbnd.getModifiers());
22 !
570
                        }else {
571
                                superTyp = this.ensureFamixType(intbnd);
4 ✔
572
                        }
573
                        
574
                        if (bnd.isInterface()) {
3 ✔
575
                                // in Java "subtyping" link between 2 interfaces is call inheritance 
576
                                lastAssociation = ensureFamixInheritance((TWithInheritances)superTyp, (TWithInheritances)fmx, lastAssociation, intbnd);
10 ✔
577
                        }
578
                        else {
579
                                lastAssociation = ensureFamixImplementation((TImplementable)superTyp, (TCanImplement)fmx, lastAssociation, intbnd);
9 ✔
580
                        }
581
                }
582
        }
1 ✔
583

584
        /**
585
         * Returns a Famix Reference between two Famix Entities creating it if needed.<br>
586
         * 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
587
         * @param src -- source of the reference
588
         * @param tgt -- target of the reference
589
         * @param prev -- previous reference relationship in the same context
590
         * @return the FamixReference
591
         */
592
        public Reference addFamixReference(Method src, TType tgt, TAssociation prev, ITypeBinding referredTypeBnd) {
593
                Reference ref = null;
2 ✔
594
                
595
                if ( (src == null) || (tgt == null) ) {
4 !
596
                        return null;
×
597
                }
598

599
                if (prev == null) {
2 ✔
600
                        for (TReference existingRef : src.getOutgoingReferences()) {
7 !
601
                                if (existingRef.getReferredEntity() == tgt) {
×
602
                                        return (Reference) existingRef;
×
603
                                }
604
                        }
×
605
                }
606

607
                if (referredTypeBnd != null) {
2 ✔
608
                        if (referredTypeBnd.isParameterizedType()) {
3 ✔
609
                                ref = (ParametricReference)buildFamixParametricAssociation(new ParametricReference(), referredTypeBnd.getErasure().getTypeParameters(), referredTypeBnd.getTypeArguments());
13 ✔
610
                        } else if (referredTypeBnd.isArray()) {
3 ✔
611
                                ref = new ParametricReference();
4 ✔
612
                        
613
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(referredTypeBnd.getElementType());
6 ✔
614
                                TypeParameter typeParameter = (TypeParameter) ((TParametricEntity)tgt).getTypeParameters().iterator().next();
7 ✔
615

616
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
617
                                ((ParametricReference)ref).addConcretization(concretization);
4 ✔
618
                        }
619
                }
620

621
                if (ref == null){
2 ✔
622
                        ref = new Reference();
4 ✔
623
                }
624

625
                ref.setReferredEntity(tgt);
3 ✔
626
                ref.setReferencer(src);
3 ✔
627
                chainPrevNext(prev,ref);
4 ✔
628
                famixRepoAdd(ref);
3 ✔
629

630
                return ref;
2 ✔
631
        }
632

633
        /**
634
         * Returns a Famix Invocation between two Famix Entities creating it if needed
635
         * @param tMethod of the invocation
636
         * @param invoked -- method invoked
637
         * @param receiver of the invocation
638
         * @param signature -- i.e. actual invocation code
639
         * @param prev -- previous invocation relationship in the same context
640
         * @return the FamixInvocation
641
         */
642
        public Invocation addFamixInvocation(TMethod tMethod, TMethod invoked, TInvocationsReceiver receiver, String signature, TAssociation prev, IMethodBinding invokedBnd) {
643
                if ( (tMethod == null) || (invoked == null) ) {
4 !
644
                        return null;
×
645
                }
646
                Invocation invocation;
647
                if (invokedBnd != null && invokedBnd.isParameterizedMethod()) {
5 ✔
648
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getTypeParameters(), invokedBnd.getTypeArguments());
13 ✔
649
                } else if ( invokedBnd != null && isConstructorBinding(invokedBnd) && invokedBnd.getMethodDeclaration().getDeclaringClass().isGenericType()) {
11 ✔
650
                        invocation = (ParametricInvocation)buildFamixParametricAssociation(new ParametricInvocation(), invokedBnd.getMethodDeclaration().getDeclaringClass().getTypeParameters(), invokedBnd.getDeclaringClass().getTypeArguments());
15 ✔
651
                } else {
652
                        invocation = new Invocation();
4 ✔
653
                }
654

655
                invocation.setReceiver(receiver);
3 ✔
656
                invocation.setSender(tMethod);
3 ✔
657
                invocation.setSignature((signature == null) ? invoked.getSignature() : signature);
5 !
658
                invocation.addCandidates(invoked);
3 ✔
659
                chainPrevNext(prev,invocation);
4 ✔
660
                famixRepoAdd(invocation);
3 ✔
661
                
662
                return invocation;
2 ✔
663
        }
664

665
        /**
666
         * Returns a Famix Access between two Famix Entities creating it if needed
667
         * @param accessor -- the entity (presumably a method) accessing the attribute
668
         * @param var -- the variable accessed
669
         * @param isWrite -- whether this is an access for reading or writing in the variable
670
         * @param prev -- previous access relationship in the same context
671
         * @return the FamixAccess
672
         */
673
        public Access addFamixAccess(TWithAccesses accessor, TStructuralEntity var, boolean isWrite, TAssociation prev) {
674
                if ( (accessor == null) || (var == null) ) {
4 !
675
                        return null;
×
676
                }
677
                Access acc = new Access();
4 ✔
678
                acc.setAccessor(accessor);
3 ✔
679
                acc.addCandidates((TAccessible) var);
3 ✔
680
                acc.setIsWrite(isWrite);
4 ✔
681
                chainPrevNext(prev, acc);
4 ✔
682
                famixRepoAdd(acc);
3 ✔
683
                
684
                return acc;
2 ✔
685
        }
686

687
        protected void chainPrevNext(TAssociation prev, TAssociation next) {
688
                if (prev != null) {
2 ✔
689
                        next.setPrevious(prev);  // not yet implemented in importer
3 ✔
690
                }
691
        }
1 ✔
692
        
693
        /**
694
         * Returns a Famix DeclaredException between a method and an Exception that it declares to throw
695
         * @param meth -- the method throwing the exception
696
         * @param excep -- the exception declared to be thrown
697
         * @return the DeclaredException
698
         */
699
        public TThrowable createFamixDeclaredException(Method meth, TThrowable excep) {
700
                if ( (meth == null) || (excep == null) ) {
4 !
701
                        return null;
×
702
                }
703
                meth.getDeclaredExceptions().add(excep);
5 ✔
704
                return excep;
2 ✔
705
        }
706

707
        /**
708
         * Returns a Famix CaughtException between a method and an Exception that is caught
709
         * @param meth -- the method catching the exception
710
         * @param excep -- the exception caught
711
         * @return the CaughtException
712
         */
713
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
714
                if ( (meth == null) || (excep == null) ) {
4 !
715
                        return null;
×
716
                }
717
                meth.getCaughtExceptions().add(excep);
5 ✔
718
                return excep;
2 ✔
719
        }
720

721
        /**
722
         * Returns a Famix ThrownException between a method and an Exception that it (actually) throws.
723
         * Note: DeclaredException indicates that the method declares it can throw the exception,
724
         * here we state that the exception is actually thrown
725
         * @param meth -- the method throwing the exception
726
         * @param excep -- the exception thrown
727
         * @return the ThrownException
728
         */
729
        public TThrowable createFamixThrownException(Method meth, TThrowable excep) {
730
                if ( (meth == null) || (excep == null) ) {
4 !
731
                        return null;
×
732
                }
733
                meth.getThrownExceptions().add(excep);
5 ✔
734
                return excep;
2 ✔
735
        }
736

737

738
        /**
739
         * Returns a Famix EntityTyping between a typed entity and a type.
740
         * @param typedEntity -- the typed entity
741
         * @param declaredType -- the declared type
742
         * @return the FamixEntityTyping
743
         */
744
        public EntityTyping ensureFamixEntityTyping(ITypeBinding declaredTypeBnd, TTypedEntity typedEntity, TType declaredType) {
745
                if ( (typedEntity == null) || (declaredType == null) ) {
4 !
746
                        return null;
2 ✔
747
                }
748
                EntityTyping typing = null;
2 ✔
749
                
750
                if (declaredTypeBnd != null) {
2 ✔
751
                        if (declaredTypeBnd.isParameterizedType()) {
3 ✔
752
                                typing = (ParametricEntityTyping)buildFamixParametricAssociation(new ParametricEntityTyping(), declaredTypeBnd.getErasure().getTypeParameters(), declaredTypeBnd.getTypeArguments());
13 ✔
753
                        }else if (declaredTypeBnd.isArray()) {
3 ✔
754
                                typing = new ParametricEntityTyping();
4 ✔
755
                                
756
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(declaredTypeBnd.getElementType());
6 ✔
757
                                TypeParameter typeParameter = (TypeParameter) ((ParametricClass)declaredType).getTypeParameters().iterator().next();
7 ✔
758

759
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
760
                                ((ParametricEntityTyping)typing).addConcretization(concretization);
4 ✔
761
                        }
762
                }
763

764
                // If we did not set a typing because not parameterized nor array, set a default one
765
                if (typing == null) {
2 ✔
766
                        typing = new EntityTyping();
4 ✔
767
                }
768
                
769
                typing.setTypedEntity(typedEntity);
3 ✔
770
                typing.setDeclaredType(declaredType);
3 ✔
771
                famixRepoAdd(typing);
3 ✔
772
                
773
                return typing;
2 ✔
774
        }
775

776

777
        ///// Special Case: ImplicitVariables /////
778

779
        /**
780
         * Returns the Famix ImplicitVariable associated to the given binding and name (self or super).
781
         * See also {@link #getEntityByKey(IBinding)}
782
         * @param bnd -- the binding
783
         * @return the Famix Entity associated to the binding or null if not found
784
         */
785
        @Deprecated
786
        public ImplicitVariable getImplicitVariableByBinding(IBinding bnd, String iv_name) {
787
                return getImplicitVariableByType((Class)getEntityByKey(bnd), iv_name);
×
788
        }
789
        
790
        /**
791
         * Returns the Famix ImplicitVariable associated to the given FamixType.
792
         * @param type -- the FamixType
793
         * @param name -- name of the ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
794
         * @return the Famix ImplicitVariable associated to the Type or null if not found
795
         */
796
        @Deprecated
797
        public ImplicitVariable getImplicitVariableByType(Type type, String name) {
798
                ImplicitVars iv = typeToImpVar.get(type);
×
799
                ImplicitVariable ret = null;
×
800
                
801
                if (iv == null) {
×
802
                        iv = new ImplicitVars();
×
803
                }
804
                
805
                if (name.equals(THIS_NAME)) {
×
806
                        ret = iv.self_iv;
×
807
                }
808
                else if (name.equals(SUPER_NAME)) {
×
809
                        ret = iv.super_iv;
×
810
                }
811

812
                return ret;
×
813
        }
814

815
        ///// Special Case: "Uniq" Entities /////
816

817
        /**
818
         * Creates or recovers a Famix Named Entity uniq for the given name.
819
         * For some specific entities we don't allow two of them with the same name.
820
         * This is the case e.g. for the default package, or the Java class "Object" and its package "java.lang".
821
         * @param fmxClass -- the Famix class of the instance to create
822
         * @param key -- a potential binding for the entity
823
         * @param name -- the name of the new instance (used if <pre>{@code bnd == null}</pre>)
824
         * @return the uniq Famix Entity for this binding and/or name
825
         */
826
        @SuppressWarnings("unchecked")
827
        public <T extends NamedEntity> T ensureFamixUniqEntity(java.lang.Class<T> fmxClass, IBinding key, String name) {
828
                T fmx = null;
2 ✔
829
                
830
                if (name == null) {
2 !
831
                        return null;
×
832
                }
833
                
834
                if (key != null) {
2 ✔
835
                        fmx = (T) getEntityByKey(key);
5 ✔
836
                }
837
                
838
                if (fmx == null) {
2 ✔
839
                        Collection<T> l = getEntityByName( fmxClass, name);
5 ✔
840
                        if (l.size() > 0) {
3 ✔
841
                                fmx = l.iterator().next();
6 ✔
842
                        }
843
                        else {
844
                                fmx = createFamixEntity(fmxClass, name);
6 ✔
845
                        }
846
                        
847
                        if (key != null) {
2 ✔
848
                                // may happen for example if the entity was first created without binding
849
                                // and we find a binding for it later
850
                                keyToEntity.put(key, fmx);
6 ✔
851
                        }
852
                }
853

854
                return fmx;
2 ✔
855
        }
856

857
        /**
858
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
859
         *
860
         * @return a Famix class
861
         */
862
        public Class ensureFamixClassStubOwner() {
863
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7 ✔
864
                if (fmx != null) {
2 !
865
                        /*if the option `useMissingPackage` is activated, we put all the stubs with unknown packages in a package `Missing*/
866
                        if(this.useMissingPackage) {
3 ✔
867
                                fmx.setTypeContainer(ensureFamixPackageMissing());
5 ✔
868
                        }
869
                        /*otherwise we put them in the default package*/
870
                        else {
871
                                fmx.setTypeContainer( ensureFamixPackageDefault());
4 ✔
872
                        }
873
                }
874
                ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
8 ✔
875

876
                return fmx;
2 ✔
877
        }
878

879
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
880
                if (ctxt == null) {
×
881
                        return null;
×
882
                }
883
                
884
                for (TType candidate : ctxt.getTypes()) {
×
885
                        if (candidate.getName().equals(name) ) {
×
886
                                return (Type) candidate;
×
887
                        }
888
                }
×
889
                
890
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
891
        }
892

893
        /**
894
         * Returns a Famix Package associated with its IPackageBinding and/or fully qualified name.
895
         * The Entity is created if it does not exist.
896
         * We assume that Namespaces must be uniq for a given name
897
         * Also creates or recovers recusively it's parent namespaces.<br>
898
         * At least one of <b>bnd</b> and <b>name</b> must be non null.
899
         *
900
         * @param bnd  -- the JDT Binding that may be used as a uniq key to recover this namespace
901
         * @param name -- fully qualified name of the namespace (e.g. 'java.lang')
902
         * @return the Famix Namespace found or created. May return null in case of a Famix error
903
         */
904
        public Package ensureFamixPackage(IPackageBinding bnd, String name) {
905
                Package fmx;
906
                Package parent;
907

908
                if ((name == null) && (bnd != null)) {
4 !
909
                        name = bnd.getName();
3 ✔
910
                }
911

912
                if ((name == null) || name.equals("")) {
6 !
913
                        return ensureFamixPackageDefault();
3 ✔
914
                } else {
915
                        /* Note: Packages are created with their fully-qualified name to simplify recovering when we don't have a binding
916
                         * (for example when creating parent packages of a package we have a binding for).
917
                         * Because the preferred solution in Moose is to give their simple names to packages, they must be post-processed when
918
                         * all is said and done. */
919
                        fmx = ensureFamixUniqEntity(Package.class, bnd, name);
7 ✔
920
                        String parentName = removeLastPartOfPackageName(name);
4 ✔
921
                        if (parentName.length() > 0) {
3 ✔
922
                                parent = ensureFamixPackage(null, parentName);
5 ✔
923
                                // set the parentscope relationship
924
                                if ((parent != null) && (fmx != null) && (fmx.getParentPackage() == null)) {
7 !
925
                                        parent.addChildEntities(fmx);
3 ✔
926
                                }
927
                        }
928
                }
929

930
                return fmx;
2 ✔
931
        }
932

933
        /**
934
         * Creates or recovers a default Famix Package.
935
         * Because this package does not really exist, it has no binding.
936
         *
937
         * @return a Famix Namespace
938
         */
939
        public Package ensureFamixPackageDefault() {
940
        return ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7 ✔
941
        }
942
        
943
        /**
944
         * Returns an artificial Package to contain stubs with an unknown package.
945
         * Always returns the same package. Create it lazily if not existing.
946
         * @return a Famix Namespace
947
         */
948
        public Package ensureFamixPackageMissing( ) {
949
                return ensureFamixUniqEntity(Package.class, null, MISSING_PCKG_NAME);
7 ✔
950
        }
951

952
        /**
953
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
954
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
955
         *
956
         * @param bnd -- a potential binding for the "java.lang" package
957
         * @return a Famix Namespace for "java.lang"
958
         */
959
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
960

961
        return this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5 ✔
962
        }
963

964
        /**
965
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
966
         */
967
        public Package getFamixPackageDefault() {
968
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5 ✔
969
                if (l.size() > 0) {
3 !
970
                        return l.iterator().next();
5 ✔
971
                } else {
972
                        return null;
×
973
                }
974
        }
975

976
        /**
977
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
978
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
979
         * @param bnd -- binding for the type to create
980
         * @param name of the type
981
         * @param owner of the type
982
         * @param ctxt -- context of use of the type
983
         */
984
        public Type ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
985
                
986
                Type fmx;
987

988
                if (bnd == null) {
2 !
989
                        if (name == null) {
×
990
                                return null;
×
991
                        }
992
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
993
                        if (fmx != null) {
×
994
                                return fmx;
×
995
                        }
996

997
                        if ((owner instanceof TParametricEntity)) {
×
998
                                return this.ensureFamixTypeParameter(null, name, owner);
×
999
                        }
1000
                        else {
1001
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1002
                                fmx.setTypeContainer(owner);
×
1003
                                return fmx;
×
1004
                        }
1005
                }
1006

1007
                // bnd != null
1008

1009
                fmx = (Type) getEntityByKey(bnd);
5 ✔
1010
                if (fmx != null) {
2 ✔
1011
                        return fmx;
2 ✔
1012
                }
1013

1014
                if (bnd.isArray()) {
3 !
1015
                        bnd = bnd.getElementType();
×
1016
                }
1017

1018
                if (bnd.isPrimitive()) {
3 ✔
1019
                        return this.ensureFamixPrimitiveType(bnd, name);
5 ✔
1020
                }
1021

1022
                if (bnd.isEnum()) {
3 !
1023
                        return this.ensureFamixEnum(bnd, name, owner);
×
1024
                }
1025
 
1026
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9 ✔
1027
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10 ✔
1028
                }
1029

1030
                if (bnd.isCapture()) {
3 ✔
1031
                        if (bnd.getErasure().isInterface()) {
4 !
1032
                                return this.ensureFamixInterface(bnd.getErasure(), name, owner, /*isGeneric*/true, modifiers);
9 ✔
1033
                        }
1034
                        else {
1035
                                return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
×
1036
                        }
1037
                }
1038

1039
                if (bnd.isAnnotation()) {
3 ✔
1040
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
7 ✔
1041
                }
1042

1043
                if (bnd.isInterface()) {
3 ✔
1044
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19 ✔
1045
                }
1046

1047
                if (isThrowable(bnd)) {
4 ✔
1048
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8 ✔
1049
                }
1050
                if (bnd.isClass()) {
3 ✔
1051
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20 !
1052
                }
1053
                if(bnd.isWildcardType()) {
3 ✔
1054
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8 ✔
1055
                }
1056

1057
                //otherwise (none of the above)
1058

1059
                if (name == null) {
2 ✔
1060
                        name = bnd.getName();
3 ✔
1061
                }
1062

1063
                if (owner == null) {
2 !
1064
                        owner = (TWithTypes) this.ensureOwner(bnd);
5 ✔
1065
                }
1066

1067
                if (bnd.isTypeVariable() ) {
3 !
1068
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6 ✔
1069
                        return fmx;
2 ✔
1070
                }
1071

1072
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1073
                fmx.setTypeContainer(owner);
×
1074
                return fmx;
×
1075
        }
1076

1077
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1078
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
6 !
1079
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8 ✔
1080
        }
1081
        
1082
        public Type ensureFamixType(ITypeBinding bnd) {
1083
                return ensureFamixType(bnd, /*ctxt*/null);
5 ✔
1084
        }
1085

1086
        public boolean isThrowable(ITypeBinding bnd) {
1087
                if (bnd == null) {
2 !
1088
                        return false;
×
1089
                }
1090
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5 ✔
1091
                        return true;
2 ✔
1092
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5 ✔
1093
                        return false;
2 ✔
1094
                }
1095
                else {
1096
                        return isThrowable(bnd.getSuperclass());
5 ✔
1097
                }
1098
        }
1099

1100
        /**
1101
         * Returns a Famix Class associated with the ITypeBinding.
1102
         * The Entity is created if it does not exist.
1103
         * @param name -- the name of the Famix Class (MUST NOT be null, but this is not checked)
1104
         * @param owner -- package defining the class (should not be null, but it will work if it is)
1105
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1106
         */
1107
        @SuppressWarnings("deprecation")
1108
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1109
                Class fmx;
1110

1111
                // --------------- some special cases
1112
                if (bnd != null) {
2 ✔
1113
                        if (bnd.isArray()) {
3 !
1114
                                bnd = bnd.getElementType();
×
1115
                        }
1116

1117
                        // for inner classes defined in generics !!! For others should not change anything
1118
                        bnd = bnd.getErasure();
3 ✔
1119
                }
1120

1121
                // ---------------- to avoid useless computations if we can
1122
                fmx = getEntityByKey(bnd, Class.class);
6 ✔
1123
                if (fmx != null) {
2 ✔
1124
                        return fmx;
2 ✔
1125
                }
1126

1127
                // --------------- name
1128
                if (name == null) {
2 ✔
1129
                        if (bnd == null) {
2 !
1130
                                return null;  // not much we can do
×
1131
                        } else if (!bnd.isAnonymous()) {
3 !
1132
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1133
                        } else { // anonymous class
1134
                                if (bnd.getSuperclass() != null) {
×
1135
                                        name = bnd.getSuperclass().getName();
×
1136
                                }
1137
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1138
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1139
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1140
                                                name = bnd.getInterfaces()[0].getName();
×
1141
                                        }
1142
                                        else {
1143
                                                name = "???";
×
1144
                                        }
1145
                                }
1146
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1147
                        }
1148
                }
1149

1150
        // If we have java.lang.Object we should ensure we create this class
1151
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7 ✔
1152
                        return ensureFamixClassObject();
3 ✔
1153
                }
1154

1155
                // --------------- owner
1156
                if (owner == null) {
2 ✔
1157
                        if (bnd != null) {
2 ✔
1158
                                owner = ensureOwner(bnd);
4 ✔
1159
                        }
1160
                        /*                                owner = ensureFamixPackageDefault();
1161
                        } else {*/
1162
                }
1163

1164
                // --------------- recover from name ?
1165
                if (owner != null) {
2 ✔
1166
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13 ✔
1167
                                if (matchAndMapClass(bnd, name, owner, candidate)) {
7 ✔
1168
                                        fmx = candidate;
2 ✔
1169
                                        break;
1 ✔
1170
                                }
1171
                        }
1 ✔
1172
                }
1173

1174
                // ---------------- create
1175
                if (fmx == null) {
2 ✔
1176
                        if (isGeneric) {
2 ✔
1177
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8 ✔
1178
                        }
1179
                        else {
1180
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7 ✔
1181
                                fmx.setTypeContainer((TWithTypes)owner);
4 ✔
1182
                        }
1183
                }
1184

1185
                // ---------------- modifiers and super-classes
1186
                if (fmx!=null) {
2 !
1187
                        // we just created it, or it was not bound so we make sure it has the right information in it
1188
                        if (bnd != null) {
2 ✔
1189
                                setClassModifiers(fmx, bnd.getDeclaredModifiers(), (TWithTypes) owner);
7 ✔
1190
                        }
1191

1192
                        TAssociation lastAssoc = null;
2 ✔
1193

1194
                        if (bnd != null) {
2 ✔
1195
                                ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1196
                                if (supbnd != null) {
2 ✔
1197
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1198
                                }
1199
                                else {
1200
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8 ✔
1201
                                }
1202
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7 ✔
1203
                        }
1204
                }
1205

1206
                return fmx;
2 ✔
1207
        }
1208

1209
        /**
1210
         * Returns a Famix Exception associated with the ITypeBinding.
1211
         * The Entity is created if it does not exist.
1212
         * @param name -- the name of the Famix Exception
1213
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1214
         *
1215
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1216
         */
1217
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1218
                Exception fmx;
1219

1220
                // --------------- some special cases
1221
                if (bnd != null) {
2 ✔
1222
                        if (bnd.isArray()) {
3 !
1223
                                bnd = bnd.getElementType();
×
1224
                        }
1225

1226
                        // for inner classes defined in generics !!! For others should not change anything
1227
                        bnd = bnd.getErasure();
3 ✔
1228
                }
1229

1230
                // ---------------- to avoid useless computations if we can
1231
                fmx = (Exception) getEntityByKey(bnd);
5 ✔
1232
                if (fmx != null) {
2 ✔
1233
                        return fmx;
2 ✔
1234
                }
1235

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

1259
                // --------------- owner
1260
                if (owner == null) {
2 ✔
1261
                        if (bnd == null) {
2 ✔
1262
                                owner = ensureFamixPackageDefault();
4 ✔
1263
                        } else {
1264
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1265
                        }
1266
                }
1267

1268
                // --------------- recover from name ?
1269
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13 ✔
1270
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8 !
1271
                                fmx = candidate;
×
1272
                                break;
×
1273
                        }
1274
                }
1 ✔
1275

1276
                // ---------------- create
1277
                if (fmx == null) {
2 !
1278
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7 ✔
1279
                        fmx.setTypeContainer(owner);
3 ✔
1280
                }
1281

1282
        // we just created it or it was not bound, so we make sure it has the right information in it
1283
        TAssociation lastAssoc = null;
2 ✔
1284
        if (bnd != null) {
2 ✔
1285
            ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1286
            if (supbnd != null) {
2 !
1287
                lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1288
            }
1289
            else {
1290
                lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
×
1291
            }
1292
            ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6 ✔
1293
        }
1294

1295
        return fmx;
2 ✔
1296
        }
1297

1298
        /**
1299
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1300
         * @param name -- the name of the FAMIX Method
1301
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1302
         * @return the FAMIX Class or null in case of a FAMIX error
1303
         */
1304
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1305
                Interface fmx;
1306

1307
                // --------------- some special cases
1308
                if (bnd != null) {
2 !
1309
                        if (bnd.isArray()) {
3 !
1310
                                bnd = bnd.getElementType();
×
1311
                        }
1312

1313
                        // for inner classes defined in generics !!! For others should not change anything
1314
                        bnd = bnd.getErasure();
3 ✔
1315
                }
1316

1317
                // ---------------- to avoid useless computations if we can
1318
                fmx = getEntityByKey(bnd, Interface.class);
6 ✔
1319
                if (fmx != null) {
2 ✔
1320
                        return fmx;
2 ✔
1321
                }
1322

1323
                // --------------- name
1324
                if (name == null) {
2 ✔
1325
                        if (bnd == null) {
2 !
1326
                                return null;  // not much we can do
×
1327
                        } else if (!bnd.isAnonymous()) {
3 !
1328
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1329
                        } else { // anonymous class
1330
                                if (bnd.getSuperclass() != null) {
×
1331
                                        name = bnd.getSuperclass().getName();
×
1332
                                }
1333
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1334
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1335
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1336
                                                name = bnd.getInterfaces()[0].getName();
×
1337
                                        }
1338
                                        else {
1339
                                                name = "???";
×
1340
                                        }
1341
                                }
1342
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1343
                        }
1344
                }
1345

1346
                // --------------- owner
1347
                if (owner == null) {
2 ✔
1348
                        if (bnd == null) {
2 !
1349
                                owner = ensureFamixPackageDefault();
×
1350
                        } else {
1351
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1352
                        }
1353
                }
1354

1355
                // --------------- recover from name ?
1356
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13 ✔
1357
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8 ✔
1358
                                fmx = candidate;
2 ✔
1359
                                break;
1 ✔
1360
                        }
1361
                }
1 ✔
1362

1363
                // ---------------- create
1364
                if (fmx == null) {
2 ✔
1365
                        if (isGeneric) {
2 ✔
1366
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7 ✔
1367
                        }
1368
                        else {
1369
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7 ✔
1370
                                fmx.setTypeContainer(owner);
3 ✔
1371
                        }
1372
                }
1373

1374
                // ---------------- modifiers and "super interfaces"
1375
                if (fmx!=null) {
2 !
1376
                        // we just created it or it was not bound, so we make sure it has the right information in it
1377
                        if (bnd != null) {
2 !
1378
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5 ✔
1379
                        }
1380
                        TAssociation lastAssociation = null;
2 ✔
1381
                        if (bnd != null) {
2 !
1382
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6 ✔
1383
                        }
1384
                }
1385
                return fmx;
2 ✔
1386
        }
1387

1388
        /**
1389
         * "Converts" (if needed) a TTYpe entity to be a TThrowable. Might involve removing the existing entity, recreating a new one and migrating
1390
         * all the relationship of the former to the later
1391
         */
1392
        public TThrowable asException(TType fmxType) {
1393
                if (fmxType instanceof Exception) {
3 ✔
1394
                        return (Exception) fmxType;
3 ✔
1395
                }
1396
                if(fmxType instanceof TypeParameter) {
3 ✔
1397
                        return (TypeParameter) fmxType;
3 ✔
1398
                }
1399

1400
                Exception fmxException = null;
2 ✔
1401
                IBinding key;
1402

1403
                try {
1404
                        key = entityToKey.get(fmxType);
6 ✔
1405

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

1410
                        TWithTypes owner = fmxType.getTypeContainer();
3 ✔
1411
                        fmxType.setTypeContainer(null);
3 ✔
1412
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10 ✔
1413

1414
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8 ✔
1415
                        if (fmxType instanceof TWithAttributes) {
3 !
1416
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8 ✔
1417
                        }
1418

1419
                        if (fmxType instanceof TWithInheritances) {
3 !
1420
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8 ✔
1421
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8 ✔
1422
                        }
1423
                        fmxException.setComments(new ArrayList<>( ((TWithComments) fmxType).getComments() ));
8 ✔
1424
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4 ✔
1425
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7 ✔
1426
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8 ✔
1427
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7 ✔
1428
                        fmxException.setIsStub(fmxType.getIsStub());
4 ✔
1429
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8 ✔
1430
                }
1431
                catch( ConcurrentModificationException e) {
×
1432
                        e.printStackTrace();
×
1433
                }
1 ✔
1434

1435
                return fmxException;
2 ✔
1436
        }
1437

1438
        /**
1439
         * helper method, we know the type exists, ensureFamixClass will recover it
1440
         */
1441
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1442
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1443
        }
1444

1445
        /**
1446
         * helper method, we know the type exists, ensureFamixInterface will recover it
1447
         */
1448
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1449
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1450
        }
1451

1452
        /**
1453
         * helper method, we know the type exists, ensureFamixInterface will recover it
1454
         */
1455
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1456
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1457
        }
1458

1459
        /**
1460
         * Ensures a famix entity for the owner of a binding.<br>
1461
         * This owner can be a method, a class or a namespace
1462
         * @param bnd -- binding for the owned entity
1463
         * @return a famix entity for the owner
1464
         */
1465
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1466
                TNamedEntity owner;
1467
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3 ✔
1468
                if (parentMtd != null) {
2 ✔
1469
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5 ✔
1470
                }
1471
                else {
1472
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3 ✔
1473
                        if (parentClass != null) {
2 ✔
1474
                owner = this.ensureFamixType(parentClass);
5 ✔
1475
            }
1476
                        else {
1477
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1478
                                if (parentPckg != null) {
2 !
1479
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1480
                                } else {
1481
                                        owner = this.ensureFamixPackageDefault();
×
1482
                                }
1483
                        }
1484
                }
1485
                return owner;
2 ✔
1486
        }
1487

1488

1489
        /**
1490
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1491
         * We assume that PrimitiveType must be uniq for a given name
1492
         * @param name -- the name of the FAMIX PrimitiveType
1493
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1494
         */
1495
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1496
                if (name == null) {
2 ✔
1497
                        if (bnd == null) {
2 !
1498
                                return null;
×
1499
                        } else {
1500
                                name = bnd.getName();
3 ✔
1501
                        }
1502
                }
1503
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7 ✔
1504
        }
1505

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

1509
                // --------------- to avoid useless computations if we can
1510
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5 ✔
1511
                if (fmx != null) {
2 ✔
1512
                        return fmx;
2 ✔
1513
                }
1514

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

1525
                // --------------- owner
1526
                if (owner == null) {
2 ✔
1527
                        if (bnd == null) {
2 !
1528
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1529
                        } else {
1530
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1531
                        }
1532
                }
1533

1534
                // --------------- recover from name ?
1535
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9 !
1536
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1537
                                fmx = candidate;
×
1538
                                break;
×
1539
                        }
1540
                }
×
1541

1542
                if (fmx == null) {
2 !
1543
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7 ✔
1544
                        fmx.setTypeContainer(owner);
3 ✔
1545
                }
1546

1547
                if (bnd != null) {
2 !
1548
                        setVisibility(fmx, bnd.getModifiers(), owner);
6 ✔
1549
                }
1550

1551
                return fmx;
2 ✔
1552
        }
1553

1554
        /**
1555
         * helper method, we know the type exists, ensureFamixEnum will recover it
1556
         */
1557
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1558
                return ensureFamixEnum(bnd, name, owner);
6 ✔
1559
        }
1560

1561
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1562
                EnumValue fmx;
1563

1564
                // --------------- to avoid useless computations if we can
1565
                fmx = (EnumValue)getEntityByKey(bnd);
5 ✔
1566
                if (fmx != null) {
2 ✔
1567
                        return fmx;
2 ✔
1568
                }
1569

1570
                // --------------- name
1571
                if (name == null) {
2 !
1572
                        if (bnd == null) {
×
1573
                                return null;
×
1574
                        }
1575
                        else {
1576
                                name = bnd.getName();
×
1577
                        }
1578
                }
1579

1580
                // --------------- owner
1581
                if (owner == null) {
2 ✔
1582
                        if (bnd == null) {
2 !
1583
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1584
                        }
1585
                        else {
1586
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7 ✔
1587
                        }
1588
                }
1589

1590
                // --------------- recover from name ?
1591
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9 !
1592
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1593
                                fmx = candidate;
×
1594
                                break;
×
1595
                        }
1596
                }
×
1597
                if (fmx == null) {
2 !
1598
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7 ✔
1599
                        fmx.setParentEnum(owner);
3 ✔
1600
                }
1601

1602
        fmx.setParentEnum(owner);
3 ✔
1603

1604
        return fmx;
2 ✔
1605
        }
1606

1607
    /**
1608
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1609
         */
1610
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1611
                AnnotationType fmx;
1612

1613
                // --------------- to avoid useless computations if we can
1614
                fmx = (AnnotationType)getEntityByKey(bnd);
5 ✔
1615
                if (fmx != null) {
2 ✔
1616
                        return fmx;
2 ✔
1617
                }
1618

1619
                // --------------- name
1620
                if (name == null) {
2 ✔
1621
                        if (bnd == null) {
2 !
1622
                                return null;
×
1623
                        }
1624
                        else {
1625
                                name = bnd.getName();
3 ✔
1626
                        }
1627
                }
1628

1629
                // --------------- owner
1630
                if (owner == null) {
2 ✔
1631
                        if (bnd == null) {
2 !
1632
                                owner = ensureFamixPackageDefault();
×
1633
                        }
1634
                        else {
1635
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1636
                                if (parentPckg != null) {
2 !
1637
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1638
                                } else {
1639
                                        owner = this.ensureFamixPackageDefault();
×
1640
                                }
1641
                        }
1642
                }
1643

1644
                // --------------- recover from name ?
1645
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13 ✔
1646
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7 !
1647
                                fmx = candidate;
2 ✔
1648
                                break;
1 ✔
1649
                        }
1650
                }
×
1651

1652
                // --------------- create
1653
                if (fmx == null) {
2 ✔
1654
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7 ✔
1655
                        fmx.setAnnotationTypesContainer(owner);
3 ✔
1656
                }
1657

1658
                if (bnd != null) {
2 !
1659
                        // Not supported in Famix
1660

1661
                        // setVisibility(fmx, bnd.getModifiers());
1662
                }
1663

1664
                return fmx;
2 ✔
1665
        }
1666

1667
        /**
1668
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1669
         */
1670
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1671
                return ensureFamixAnnotationType(bnd, name, owner);
6 ✔
1672
        }
1673

1674
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1675
                AnnotationTypeAttribute fmx = null;
2 ✔
1676

1677
                // --------------- to avoid useless computations if we can
1678
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5 ✔
1679
                if (fmx != null) {
2 ✔
1680
                        return fmx;
2 ✔
1681
                }
1682

1683
                // --------------- name
1684
                if (name == null) {
2 !
1685
                        if (bnd == null) {
×
1686
                                return null;
×
1687
                        }
1688
                        else {
1689
                                name = bnd.getName();
×
1690
                        }
1691
                }
1692

1693
                // --------------- owner
1694
                if (owner == null) {
2 !
1695
                        if (bnd == null) {
×
1696
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1697
                        }
1698
                        else {
1699
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1700
                                if (parentType != null) {
×
1701
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1702
                                }
1703
                                else  {
1704
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1705
                                }
1706
                        }
1707
                }
1708

1709
                // --------------- recover from name ?
1710
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13 ✔
1711
                        // JDT treats annotation type attributes as methods ...
1712
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1713
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11 !
1714
                                fmx = candidate;
×
1715
                                break;
×
1716
                        }
1717
                        // if the binding is null, the annotationTypeAttribute migth have been created
1718
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2 !
1719
                                fmx = candidate;
×
1720
                                break;
×
1721
                        }
1722
                }
1 ✔
1723

1724
                if (fmx == null) {
2 !
1725
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7 ✔
1726
                        fmx.setParentType(owner);
3 ✔
1727
                }
1728

1729
                if (bnd != null) {
2 !
1730
                        // Not suopp
1731

1732
                        // setVisibility(fmx, bnd.getModifiers());
1733
                }
1734

1735
                return fmx;
2 ✔
1736
        }
1737

1738
        /**
1739
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1740
         */
1741
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1742
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6 ✔
1743
        }
1744
        
1745
        
1746
        /**
1747
         * Returns a FAMIX Wildcard with its bounds
1748
         * @param bnd
1749
         * @param name
1750
         * @param owner
1751
         * @return
1752
         */
1753
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1754
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8 ✔
1755
                if(bnd.getBound() != null) {
3 ✔
1756
                        Type bound = this.ensureFamixType(bnd.getBound());
5 ✔
1757
                        if(bnd.isUpperbound()) {
3 ✔
1758
                                fmx.setUpperBound(bound);
3 ✔
1759
                                bound.addUpperBoundedWildcards(fmx);
4 ✔
1760
                        }else{
1761
                                fmx.setLowerBound(bound);
3 ✔
1762
                                bound.addLowerBoundedWildcards(fmx);
3 ✔
1763
                        }
1764
                }
1765
                return fmx;
2 ✔
1766
        }
1767

1768
        /**
1769
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1770
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1771
         * @param name -- the name of the Famix TypeParameter
1772
         * @return the Famix TypeParameter or null in case of a Famix error
1773
         */
1774
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1775
                TypeParameter fmx;
1776

1777
                // --------------- to avoid useless computations if we can
1778
                fmx = (TypeParameter)getEntityByKey(bnd);
5 ✔
1779
                if (fmx != null) {
2 ✔
1780
                        return fmx;
2 ✔
1781
                }
1782

1783
                // --------------- name
1784
                if (name == null) {
2 ✔
1785
                        if (bnd == null) {
2 !
1786
                                return null;
×
1787
                        }
1788
                        else {
1789
                                name = bnd.getName();
3 ✔
1790
                        }
1791
                }
1792

1793
                // --------------- owner
1794
                if (owner == null && bnd != null) {
2 !
1795
            if (bnd.getDeclaringClass() != null) {
×
1796
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
1797
            } else if(bnd.getDeclaringMethod() != null) {
×
1798
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1799
            }
1800
                }
1801

1802
                // --------------- recover from name ?
1803
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13 ✔
1804
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8 ✔
1805
                                fmx = (TypeParameter) candidate;
3 ✔
1806
                                break;
1 ✔
1807
                        }
1808
                }
1 ✔
1809

1810
                // --------------- create
1811
                if (fmx == null) {
2 ✔
1812
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7 ✔
1813
                        if(bnd != null && bnd.getSuperclass() != null) {
5 !
1814
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5 ✔
1815
                                fmx.setUpperBound(upperBound);
3 ✔
1816
                        }
1817
                        if(bnd != null) {
2 ✔
1818
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17 ✔
1819
                    Type upperBound = ensureFamixType(intbnd);
4 ✔
1820
                    fmx.setUpperBound(upperBound);
3 ✔
1821
                }
1822
            }
1823
                        fmx.setTypeContainer(owner);
3 ✔
1824
                }
1825

1826
                return fmx;
2 ✔
1827
        }
1828

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

1844
                // check whether bnd and candidate are already bound
1845
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1846
                if (res == CheckResult.MATCH) {
3 ✔
1847
                        return true;
2 ✔
1848
                } else if (res == CheckResult.FAIL) {
3 ✔
1849
                        return false;
2 ✔
1850
                }
1851

1852
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
1853
                        return false;
2 ✔
1854
                }
1855

1856
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1857
                conditionalMapToKey(bnd, candidate);
4 ✔
1858
                return true;
2 ✔
1859
        }
1860

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

1876
                // check whether bnd and candidate are already bound
1877
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1878
                if (res == CheckResult.MATCH) {
3 ✔
1879
                        return true;
2 ✔
1880
                }
1881
                else if (res == CheckResult.FAIL) {
3 ✔
1882
                        return false;
2 ✔
1883
                }
1884

1885
                if ( (bnd != null) && (bnd.isArray()) ) {
5 ✔
1886
                                bnd = bnd.getElementType();
3 ✔
1887
                }
1888

1889
                // checking names
1890
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8 !
1891
                        name = bnd.getErasure().getName();
×
1892
                }
1893
                else if (bnd != null) {
2 ✔
1894
                        name = bnd.getName();
3 ✔
1895
                }
1896
                // else name = name
1897
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7 ✔
1898
                        return false;
2 ✔
1899
                }
1900

1901
                // special case of primitive types
1902
                if (candidate instanceof PrimitiveType) {
3 !
1903
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1904
                                // names are equal so it's OK
1905
                                conditionalMapToKey(bnd, candidate);
×
1906
                                return true;
×
1907
                        }
1908
                        else if ( (bnd == null) && (owner == null) ) {
×
1909
                                return true;
×
1910
                        }
1911
                }
1912

1913
                // check owners without bnd
1914
                if (bnd == null) {
2 ✔
1915
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1916
                }
1917

1918
                // check owners with bnd
1919
                // type is an annotation
1920
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6 !
1921
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13 !
1922
                                conditionalMapToKey(bnd, candidate);
4 ✔
1923
                                return true;
2 ✔
1924
                        } else {
1925
                                return false;
×
1926
                        }
1927
                }
1928

1929
                // check owners with bnd
1930
                // type is a Parameterized type
1931
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
6 !
1932
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1933
                }
1934

1935
                // check owners with bnd
1936
                // type is an Enum
1937
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3 !
1938
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1939
                }
1940

1941
                // check owners with bnd
1942
                // type is something elae (a class or interface)
1943
                // Annotation are interfaces too, so we should check this one after isAnnotation
1944
                if ( bnd.isClass()) {
3 !
1945
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1946
                }
1947

1948
                if(bnd.isInterface()) {
3 !
1949
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
×
1950
                }
1951

1952
                return false;
2 ✔
1953
        }
1954

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

1969
                // check whether bnd and candidate are already bound
1970
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1971
                if (res == CheckResult.MATCH) {
3 ✔
1972
                        return true;
2 ✔
1973
                } else if (res == CheckResult.FAIL) {
3 ✔
1974
                        return false;
2 ✔
1975
                }
1976

1977
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
1978
                        return false;
×
1979
                }
1980

1981
                // checking owner
1982
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1983
        }
1984

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

1999
                // check whether bnd and candidate are already bound
2000
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
2001
                if (res == CheckResult.MATCH) {
3 ✔
2002
                        return true;
2 ✔
2003
                } else if (res == CheckResult.FAIL) {
3 ✔
2004
                        return false;
2 ✔
2005
                }
2006

2007
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
2008
                        return false;
×
2009
                }
2010

2011
                // checking owner
2012
                return matchAndMapTypeOwner(bnd, owner, candidate);
6 ✔
2013
        }
2014

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

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

2040
                // checking names
2041
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10 !
2042
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
2043
                        return false;
2 ✔
2044
                }
2045

2046
                // for methods, the name is not enough, we must test the signature also
2047
                // but not for AnnotationTypeAttribute
2048

2049
                        if (bnd != null) {
2 ✔
2050
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7 ✔
2051
                        }
2052
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6 ✔
2053
                                return false;
2 ✔
2054
                        }
2055

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

2090

2091
                // check owner
2092
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13 ✔
2093
                        conditionalMapToKey(bnd, candidate);
4 ✔
2094
                        return true;
2 ✔
2095
                } else {
2096
                        return false;
2 ✔
2097
                }
2098
        }
2099

2100
        /** testing that a method binding is for a constructor
2101
         * There is a special case for "diamond constructors" (eg: <code>new HashSet<>()</code>)
2102
         */
2103
        protected boolean isConstructorBinding(IMethodBinding bnd) {
2104
                if (bnd.isConstructor()) {
3 ✔
2105
                        return true;
2 ✔
2106
                }
2107
                if ( bnd.getName().equals("<factory>") ) {
5 ✔
2108
                        return true;
2 ✔
2109
                }
2110
                return false;
2 ✔
2111
        }
2112

2113
        /**
2114
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2115
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2116
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2117
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2118
         * @param name of the variable
2119
         * @param owner of the variable
2120
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2121
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2122
         */
2123
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2124
                if (!(candidate instanceof TStructuralEntity)) {
3 !
2125
                        return false;
×
2126
                }
2127

2128
                // check whether bnd and candidate are already bound
2129
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5 ✔
2130
                if (keyMatch == CheckResult.MATCH) {
3 !
2131
                        return true;
×
2132
                } else if (keyMatch == CheckResult.FAIL) {
3 ✔
2133
                        return false;
2 ✔
2134
                }
2135

2136
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
2137
                        return false;
×
2138
                }
2139

2140
                // check owner
2141
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3 ✔
2142

2143
                // local variable or parameter ?
2144
                // owner is a Method? (for example in case of an anonymous class)
2145
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11 ✔
2146
                if (res == CheckResult.FAIL) {
3 ✔
2147
                        return false;
2 ✔
2148
                } else if (res == CheckResult.MATCH) {
3 !
2149
                        conditionalMapToKey(bnd, candidate);
×
2150
                        return true;
×
2151
                }
2152

2153
                // check owner
2154
                // <anArray>.length field?
2155
                if (name.equals("length")) {
4 !
2156
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2157
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2158
                        if (isArrayLengthField) {
×
2159
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2160
                                        conditionalMapToKey(bnd, candidate);
×
2161
                                        return true;
×
2162
                                }
2163
                                else {
2164
                                        return false;
×
2165
                                }
2166
                        }
2167
                }
2168

2169
                // check owner
2170
                // "normal" field?
2171
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2172
                if (res == CheckResult.MATCH) {
3 !
2173
                        conditionalMapToKey(bnd, candidate);
4 ✔
2174
                        return true;
2 ✔
2175
                }
2176
                return false;
×
2177
        }
2178

2179
        /**
2180
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2181
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2182
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2183
         * @param owner -- the owner of the type
2184
         * @param candidate -- a Famix Entity
2185
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2186
         */
2187
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2188
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4 ✔
2189

2190
                // owner is a Method? (for example in case of an anonymous class)
2191
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11 ✔
2192
                if (res == CheckResult.MATCH) {
3 !
2193
                        conditionalMapToKey(bnd, candidate);
×
2194
                        return true;
×
2195
                } else if (res == CheckResult.FAIL) {
3 !
2196
                        return false;
×
2197
                }
2198

2199
                // owner is a class ?
2200
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2201
                if (res == CheckResult.MATCH) {
3 ✔
2202
                        conditionalMapToKey(bnd, candidate);
4 ✔
2203
                        return true;
2 ✔
2204
                }
2205
                else if (res == CheckResult.FAIL) {
3 ✔
2206
                        return false;
2 ✔
2207
                }
2208

2209
                // owner must be a package
2210
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12 ✔
2211
                        conditionalMapToKey(bnd, candidate);
4 ✔
2212
                        return true;
2 ✔
2213
                }
2214
                return false;
2 ✔
2215
        }
2216

2217
        /**
2218
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2219
         * @param methBnd
2220
         * @param owner
2221
         * @param candidateOwner
2222
         * @return a {@link CheckResult}
2223
         */
2224
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2225
                if ((methBnd != null) || (owner instanceof Method)) {
5 !
2226
                        if (!(candidateOwner instanceof Method)) {
3 !
2227
                                return CheckResult.FAIL;
×
2228
                        }
2229

2230
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7 !
2231
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7 !
2232
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8 !
2233

2234
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9 !
2235
                                return CheckResult.MATCH;
×
2236
                        } else {
2237
                                return CheckResult.FAIL;
2 ✔
2238
                        }
2239
                }
2240
                return CheckResult.UNDECIDED;
2 ✔
2241
        }
2242

2243
        /**
2244
         * @param typBnd
2245
         * @param owner
2246
         * @param candidateOwner
2247
         * @return a {@link CheckResult}
2248
         */
2249
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2250
                if ((typBnd != null) || (owner instanceof Type)) {
5 ✔
2251
                        if (!(candidateOwner instanceof Type)) {
3 ✔
2252
                                return CheckResult.FAIL;
2 ✔
2253
                        }
2254

2255
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6 !
2256
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2257

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

2267
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2268
                if ((pckgBnd != null) || (owner instanceof Package)) {
5 !
2269
                        if (!(candidateOwner instanceof Package)) {
3 !
2270
                                return CheckResult.FAIL;
×
2271
                        }
2272

2273
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7 !
2274
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2275

2276
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7 ✔
2277
                                return CheckResult.MATCH;
2 ✔
2278
                        } else {
2279
                                return CheckResult.FAIL;
2 ✔
2280
                        }
2281
                }
2282
                return CheckResult.UNDECIDED;
×
2283
        }
2284

2285
        /**
2286
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2287
         * 'name' and 'bnd' cannot be null together
2288
         * @param bnd -- binding associated with the entity may be null
2289
         * @param name -- name of the entity may be null
2290
         * @param candidate
2291
         * @return true if names match, false if not
2292
         */
2293
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2294
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8 ✔
2295
                        return CheckResult.FAIL;
2 ✔
2296
                }
2297
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9 !
2298
                        return CheckResult.FAIL;
2 ✔
2299
                }
2300
                else {
2301
                        return CheckResult.MATCH;
2 ✔
2302
                }
2303
        }
2304

2305
        /**
2306
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2307
         * @param key
2308
         * @param candidate
2309
         * @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>
2310
         */
2311
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2312
                if (key == null) {
2 ✔
2313
                        return CheckResult.UNDECIDED;
2 ✔
2314
                }
2315

2316
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5 ✔
2317
                if (bound == candidate) {
3 ✔
2318
                        return CheckResult.MATCH;
2 ✔
2319
                }
2320
                else if (bound != null) {
2 ✔
2321
                        return CheckResult.FAIL;
2 ✔
2322
                }
2323
                else if (getEntityKey(candidate) != null) {
4 ✔
2324
                        //we check if the both bindings are linked to the same entity
2325
                        IBinding candidateBinding = getEntityKey(candidate);
4 ✔
2326
                        if(candidateBinding.getKey().equals(key.getKey())) {
6 ✔
2327
                                return CheckResult.MATCH;
2 ✔
2328
                        }
2329
                        
2330
                        //if candidate is a stub, we accept multiple recovery binding
2331
                        //this code will be upgraded with the possibility to add manually code to entities
2332
                        if (candidate instanceof TCanBeStub && ((TCanBeStub) candidate).getIsStub()) {
8 !
2333
                                return CheckResult.UNDECIDED;
2 ✔
2334
                        }
2335
      
2336
                        return CheckResult.FAIL;
2 ✔
2337
                }
2338
                else {
2339
                        return CheckResult.UNDECIDED;
2 ✔
2340
                }
2341
        }
2342

2343
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2344
                if (bnd != null) {
2 ✔
2345
                        mapEntityToKey(bnd, ent);
4 ✔
2346
                }
2347
        }
1 ✔
2348

2349
        public Method ensureFamixMethod(IMethodBinding bnd) {
2350
                return ensureFamixMethod(
8 ✔
2351
                                bnd,
2352
                                /*name*/null,
2353
                                /*paramsType*/null,
2354
                                /*returnType*/null,
2355
                                /*owner*/null,
2356
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6 ✔
2357
        }
2358

2359
        /**
2360
         * Returns a Famix Method associated with the IMethodBinding.
2361
         * The Entity is created if it does not exist.
2362
         * @param name -- the name of the Famix Method (MUST NOT be null, but this is not checked)
2363
         * @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)
2364
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2365
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2366
         */
2367
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2368
                Method fmx;
2369
                String signature;
2370
                boolean delayedRetTyp;
2371

2372
                // --------------- to avoid useless computations if we can
2373
                fmx = (Method)getEntityByKey(bnd);
5 ✔
2374
                if (fmx != null) {
2 ✔
2375
                        return fmx;
2 ✔
2376
                }
2377

2378
                // --------------- name
2379
                if (name == null) {
2 ✔
2380
                        if (bnd == null) {
2 ✔
2381
                                return null;
2 ✔
2382
                        }
2383
                        else {
2384
                                name = bnd.getName();
3 ✔
2385
                        }
2386
                }
2387

2388
                // --------------- signature
2389
                signature = name + "(";
3 ✔
2390
                 if (bnd != null) {
2 ✔
2391
                    signature += signatureParamsFromBinding(bnd);
7 ✔
2392
                }
2393
        else if (paramTypes != null) {
2 !
2394
                        signature += signatureParamsFromStringCollection(paramTypes);
7 ✔
2395
                }
2396
                else {
2397
                        signature += "???";
×
2398
                }
2399
                signature += ")";
3 ✔
2400

2401
                // --------------- return type
2402
                delayedRetTyp = false;
2 ✔
2403
                ITypeBinding retTypBnd = null;
2 ✔
2404
                if (ret == null) {
2 !
2405
                        if (bnd != null) {
2 ✔
2406
                // must create the return type
2407
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2408
                // we need T to create the method and the method to create T ...
2409
                // so we need to test the situation and deal with it
2410
                retTypBnd = bnd.getReturnType();
3 ✔
2411
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9 ✔
2412
                    delayedRetTyp = true;
3 ✔
2413
                }
2414
                else {
2415
                        ret = this.referredType(retTypBnd, fmx);
5 ✔
2416
                }
2417
                        }
2418
                }
2419

2420
                // --------------- owner
2421
                if (owner == null) {
2 ✔
2422
                        if (bnd == null) {
2 ✔
2423
                                owner = ensureFamixClassStubOwner();
4 ✔
2424
                        }
2425
                        else {
2426
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4 ✔
2427
                                if (classBnd != null) {
2 !
2428
                                        owner = ensureFamixType(classBnd);
5 ✔
2429
                                }
2430
                                else {
2431
                                        owner = ensureFamixClassStubOwner();
×
2432
                                }
2433
                        }
2434
                }
2435

2436
                // --------------- recover from name ?
2437
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13 ✔
2438
                        if (matchAndMapMethod(bnd, signature, ret, (TNamedEntity) owner, candidate)) {
9 ✔
2439
                                fmx = candidate;
2 ✔
2440
                                break;
1 ✔
2441
                        }
2442
                }
1 ✔
2443

2444
                if (fmx == null) {
2 ✔
2445
                        if(bnd != null && bnd.isGenericMethod() && !isConstructorBinding(bnd)) {
9 ✔
2446
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7 ✔
2447
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18 ✔
2448
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6 ✔
2449
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4 ✔
2450
                                }
2451
                        // Parameterized method binding = when the method is the target of an invocation.
2452
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5 ✔
2453
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
6 ✔
2454
                        } else {
2455
                if (bnd != null && isConstructorBinding(bnd)) {
6 ✔
2456
                    fmx = ensureFamixEntity(Initializer.class, bnd, name);
8 ✔
2457
                } else {
2458
                    fmx = ensureFamixEntity(Method.class, bnd, name);
7 ✔
2459
                }
2460
            }
2461

2462
                        fmx.setSignature(signature);
3 ✔
2463
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7 ✔
2464
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6 ✔
2465
                        fmx.setParentType(owner);
3 ✔
2466
                }
2467

2468
                if (fmx != null) {
2 !
2469
                        setMethodModifiers(fmx, modifiers);
4 ✔
2470
                }
2471

2472
        //If it has the #default keywork, we mark it as default implementation
2473
        if (Modifier.isDefault(modifiers)) {
3 ✔
2474
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3 ✔
2475
        }
2476

2477
        if (delayedRetTyp) {
2 ✔
2478
                        int retTypModifiers = retTypBnd.getModifiers();
3 ✔
2479
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3 ✔
2480
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13 ✔
2481
                }
2482

2483
                return fmx;
2 ✔
2484
        }
2485

2486

2487
        /**
2488
         * Creates or recovers the initializer method containing the attribute initializations of a type.
2489
         * @param owner Type containing the initializer
2490
         * @param isStatic Modifier of the initializer. A type can have 2 initializers for attribute initialization: 1 static and 1 not.
2491
         * @param isInitializationBlock True if the entity is an initialization block. False for the artificial method containing all field initializations.
2492
         * @return the FamixInitializer
2493
         */
2494
        public Initializer ensureFamixInitializer(TWithMethods owner, Boolean isStatic, Boolean isInitializationBlock) {
2495
                Initializer fmx = null;
2 ✔
2496

2497
                if (owner != null) {
2 !
2498
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
6 ✔
2499
                                        .filter(meth ->
1 ✔
2500
                                                        ((Method) meth).getIsInitializer() &&
8 ✔
2501
                                                        ((Method) meth).getIsConstructor().equals(false) &&
7 ✔
2502
                                                        ((Method) meth).getIsClassSide().equals(isStatic) &&
6 ✔
2503
                                                        ((Initializer) meth).getIsInitializationBlock().equals(isInitializationBlock))
7 ✔
2504
                                        .findFirst();
2 ✔
2505
                        if (existingInitializer.isPresent()) {
3 ✔
2506
                                fmx = (Initializer) existingInitializer.get();
4 ✔
2507
                        }
2508
                }
2509

2510
                if (fmx == null) {
2 ✔
2511
                        fmx = createFamixEntity(Initializer.class, INIT_BLOCK_NAME);
6 ✔
2512
                        fmx.setSignature(INIT_BLOCK_NAME + "()" );
3 ✔
2513
                        fmx.setVisibility(MODIFIER_PRIVATE);
3 ✔
2514
                        fmx.setParentType(owner);
3 ✔
2515
                        fmx.setIsClassSide(isStatic);
3 ✔
2516
                        fmx.setIsInitializationBlock(isInitializationBlock);
3 ✔
2517
                }
2518

2519
                return fmx;
2 ✔
2520
        }
2521

2522

2523
        public Initializer ensureImplicitConstructor(IMethodBinding binding, TWithMethods owner, String name, Collection<String> parameterTypesNames) {
2524
                Initializer fmx = null;
2 ✔
2525

2526
                if (fmx == null) {
2 !
2527
                        int modifiers = (binding != null) ? binding.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
7 ✔
2528
                        if (binding == null) {
2 ✔
2529
                                // OK! Binding is null, this is the default constructor!!
2530
                                // It has no source code :)
2531
                                fmx = ensureFamixEntity(Initializer.class, null, name);
7 ✔
2532
                                fmx.setParentType(owner);
3 ✔
2533
                                fmx.setSignature(name + "()");                                
5 ✔
2534
                        } else {
2535
                                // But, if we have the binding, that means the constructor exists. Let's just go the normal way
2536
                                fmx = (Initializer) this.ensureFamixMethod(binding, name, parameterTypesNames, /*ret type*/null, owner, modifiers);
10 ✔
2537
                        }
2538
                }
2539

2540
                return fmx;
2 ✔
2541
        }
2542

2543
        /**
2544
         * Creates or recovers a stub Famix Method
2545
         * @param name of the method
2546
         * @return the Famix Method
2547
         */
2548
        public Method ensureFamixStubMethod(String name) {
2549
                return ensureFamixMethod(null, name, /*paramType*/null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);
×
2550
        }
2551

2552
        public void setAttributeModifiers(Attribute fmx, int mod) {
2553
                setCommonModifiers(fmx, mod, null);
5 ✔
2554
                fmx.setIsTransient(Modifier.isTransient(mod));
5 ✔
2555
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5 ✔
2556
        }
1 ✔
2557

2558
        public void setMethodModifiers(Method fmx, int mod) {
2559
                setCommonModifiers(fmx, mod, (TWithTypes) fmx.getParentType());
7 ✔
2560
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2561
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5 ✔
2562
        }
1 ✔
2563

2564
        public void setClassModifiers(Class fmx, int mod, TWithTypes owner) {
2565
                setCommonModifiers(fmx, mod, null);
5 ✔
2566
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2567
        }
1 ✔
2568

2569
        public void setInterfaceModifiers(Interface fmx, int mod) {
2570
                setCommonModifiers(fmx, mod, null);
5 ✔
2571
        }
1 ✔
2572

2573
        private void setCommonModifiers(Entity fmx, int mod, TWithTypes owner) {
2574
                setVisibility((THasVisibility)fmx, mod, owner);
6 ✔
2575
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6 ✔
2576
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6 ✔
2577
        }
1 ✔
2578

2579
        /**
2580
         * Sets the visibility of a FamixNamedEntity
2581
         *
2582
         * @param fmx -- the FamixNamedEntity
2583
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2584
         */
2585
        public void setVisibility(THasVisibility fmx, int mod, TWithTypes owner) {
2586
                if (Modifier.isPublic(mod)) {
3 ✔
2587
                        fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2588
                } else if (Modifier.isPrivate(mod)) {
3 ✔
2589
                        fmx.setVisibility(MODIFIER_PRIVATE);
4 ✔
2590
                } else if (Modifier.isProtected(mod)) {
3 ✔
2591
                        fmx.setVisibility(MODIFIER_PROTECTED);
4 ✔
2592
                } else {
2593
                        //Default visibility!
2594
                        //If we are in an interface, default visibility is public, otherwise package.
2595
                        if (owner instanceof Interface) {
3 ✔
2596
                                fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2597
                        } else {
2598
                                fmx.setVisibility(MODIFIER_PACKAGE);
3 ✔
2599
                        }
2600
                }
2601
        }
1 ✔
2602

2603
        /**
2604
         * Returns a Famix Attribute associated with the IVariableBinding.
2605
         * The Entity is created if it does not exist.<br>
2606
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2607
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2608
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2609
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2610
         */
2611
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2612
                Attribute fmx;
2613

2614
                // --------------- to avoid useless computations if we can
2615
                fmx = (Attribute)getEntityByKey(bnd);
5 ✔
2616
                if (fmx != null) {
2 ✔
2617
                        return fmx;
2 ✔
2618
                }
2619

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

2630
                // --------------- owner
2631
                if (owner == null) {
2 ✔
2632
                        if (bnd == null) {
2 !
2633
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2634
                        }
2635
                        else {
2636
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7 !
2637
                                        // Declaring class is the generic one if the class is parametric.
2638
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8 ✔
2639
                                } else {
2640
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2 ✔
2641
                                }
2642
                        }
2643
                }
2644

2645
                // --------------- recover from name ?
2646
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13 ✔
2647
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8 ✔
2648
                                fmx = candidate;
2 ✔
2649
                                break;
1 ✔
2650
                        }
2651
                }
1 ✔
2652

2653
                if (fmx == null) {
2 ✔
2654
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7 ✔
2655
                        fmx.setParentType( owner);
3 ✔
2656
                }
2657

2658
        fmx.setParentType(owner);
3 ✔
2659
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7 ✔
2660
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6 ✔
2661
        if (bnd != null) {
2 ✔
2662
            int mod = bnd.getModifiers();
3 ✔
2663
            setAttributeModifiers(fmx, mod);
4 ✔
2664
        }
2665

2666
        return fmx;
2 ✔
2667
        }
2668

2669
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2670
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2671
        }
2672

2673
        /**
2674
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2675
         */
2676
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2677
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2678
        }
2679

2680
        /**
2681
         * Returns a Famix Parameter associated with the IVariableBinding.
2682
         * The Entity is created if it does not exist.<br>
2683
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2684
         */
2685
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2686
                Parameter fmx = null;
2 ✔
2687

2688
                // --------------- to avoid useless computations if we can
2689
                try {
2690
                        fmx = (Parameter)getEntityByKey(bnd);
5 ✔
2691
                }catch(Throwable e) {
×
2692
                        e.printStackTrace();
×
2693
                }
1 ✔
2694
                if (fmx != null) {
2 ✔
2695
                        return fmx;
2 ✔
2696
                }
2697

2698
                // --------------- name
2699
                if (name == null) {
2 !
2700
                        if (bnd == null) {
×
2701
                                return null;
×
2702
                        }
2703
                        else {
2704
                                name = bnd.getName();
×
2705
                        }
2706
                }
2707

2708
                // --------------- owner
2709
                if (tMethod == null) {
2 !
2710
                        if (bnd == null) {
×
2711
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2712
                        }
2713
                        else {
2714
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2715
                        }
2716
                }
2717

2718
                // --------------- recover from name ?
2719
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13 ✔
2720
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7 !
2721
                                fmx = candidate;
×
2722
                                break;
×
2723
                        }
2724
                }
1 ✔
2725

2726
                if (fmx == null) {
2 !
2727
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7 ✔
2728
                }
2729

2730
                if (fmx != null) {
2 !
2731
                        fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2732
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5 !
2733
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6 ✔
2734
                }
2735

2736
                return fmx;
2 ✔
2737
        }
2738

2739
    /**
2740
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2741
         * The Entity is created if it does not exist.<br>
2742
         * @param name -- the name of the FAMIX LocalVariable
2743
         * @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
2744
         */
2745
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2746
                LocalVariable fmx;
2747

2748
                // --------------- to avoid useless computations if we can
2749
                fmx = (LocalVariable)getEntityByKey(bnd);
5 ✔
2750
                if (fmx != null) {
2 !
2751
                        return fmx;
×
2752
                }
2753

2754
                // --------------- name
2755
                if (name == null) {
2 !
2756
                        if (bnd == null) {
×
2757
                                return null;
×
2758
                        }
2759
                        else {
2760
                                name = bnd.getName();
×
2761
                        }
2762
                }
2763

2764
                // --------------- owner
2765
                if (owner == null) {
2 !
2766
                        if (bnd == null) {
×
2767
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2768
                        }
2769
                        else {
2770
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2771
                        }
2772
                }
2773

2774
                // --------------- recover from name ?
2775
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13 ✔
2776
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8 !
2777
                                fmx = candidate;
×
2778
                                break;
×
2779
                        }
2780
                }
1 ✔
2781

2782
                if (fmx == null) {
2 !
2783
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7 ✔
2784
                        fmx.setParentBehaviouralEntity(owner);
3 ✔
2785
                }
2786

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

2790
        return fmx;
2 ✔
2791
        }
2792

2793
    /**
2794
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2795
         * If this ImplicitVariable does not exist yet, it is created
2796
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2797
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2798
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2799
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2800
         */
2801
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2802
                ImplicitVariable fmx;
2803
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7 ✔
2804
                fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2805
                return fmx;
2 ✔
2806
        }
2807

2808
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2809
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4 ✔
2810
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7 ✔
2811
        }
2812

2813
        /**
2814
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2815
         * @param jCmt -- the content (String) of the comment 
2816
         * @param owner -- the entity that is commented
2817
         * @return the Famix Comment
2818
         */
2819
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2820
                Comment cmt = null;
2 ✔
2821

2822
                if ( (jCmt != null) && (owner != null) ) {
4 !
2823
                        
2824
                        cmt = new Comment();
4 ✔
2825
                        addSourceAnchor(cmt, jCmt);
5 ✔
2826
                        famixRepoAdd(cmt);
3 ✔
2827
                        cmt.setCommentedEntity(owner);
3 ✔
2828
                }
2829

2830
                return cmt;
2 ✔
2831
        }
2832

2833
        /**
2834
         * Creates and returns a Famix Comment and associates it with an Entity
2835
         * @param jCmt -- the content (String) of the comment 
2836
         * @param owner -- the entity that is commented
2837
         * @param content -- the text of the comment
2838
         * @return the Famix Comment
2839
         */
2840
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2841
                Comment cmt = null;
2 ✔
2842

2843
                if ( (jCmt != null) && (owner != null) ) {
4 !
2844
                        cmt = new Comment();
4 ✔
2845
                        cmt.setContent(content );
3 ✔
2846
                        famixRepoAdd(cmt);
3 ✔
2847
                        cmt.setCommentedEntity(owner);
3 ✔
2848
                }
2849

2850
                return cmt;
2 ✔
2851
        }
2852

2853
        /**
2854
         * Adds location information to a Famix Entity.
2855
         * 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.
2856
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2857
         * @param fmx -- Famix Entity to add the anchor to
2858
         * @param node -- JDT ASTNode, where the information is extracted
2859
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2860
         */
2861
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2862
                IndexedFileAnchor fa;
2863

2864
                fa = createIndexedFileAnchor(node);
4 ✔
2865
                if ((fmx != null) && (fa != null)) {
4 !
2866
                        fmx.setSourceAnchor(fa);
3 ✔
2867
                        famixRepoAdd(fa);
3 ✔
2868
                }
2869

2870
                return fa;
2 ✔
2871
        }
2872

2873
        /**
2874
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2875
         */
2876
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2877
                IndexedFileAnchor fa;
2878

2879
                fa = createIndexedFileAnchor(node);
4 ✔
2880
                if ((fmx != null) && (fa != null)) {
4 !
2881

2882
                        // may change the positions
2883
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4 ✔
2884
                        methodDeclarationModifiers.addAll(node.modifiers());
5 ✔
2885
                        if (node.getName() != null) {
3 !
2886
                                methodDeclarationModifiers.add(node.getName());
5 ✔
2887
                        }
2888
                        if (node.getReturnType2() != null) {
3 ✔
2889
                                methodDeclarationModifiers.add(node.getReturnType2());
5 ✔
2890
                        }
2891
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12 ✔
2892
                        int end = node.getStartPosition() + node.getLength();
6 ✔
2893

2894
                        fa.setStartPos(beg);
4 ✔
2895
                        fa.setEndPos(end);
4 ✔
2896

2897
                        fmx.setSourceAnchor(fa);
3 ✔
2898
                        famixRepoAdd(fa);
3 ✔
2899
                }
2900

2901
                return fa;
2 ✔
2902
        }
2903

2904
        /**
2905
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2906
         * Information returned in the form of an IndexedFileAnchor
2907
         */
2908
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2909
                IndexedFileAnchor fa;
2910
                
2911
                if (node == null) {
2 !
2912
                        return null;
×
2913
                }
2914

2915
                // position in source file
2916
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5 ✔
2917
                int end = beg + node.getLength() - 1;
7 ✔
2918

2919
                // find source Compilation Unit
2920
                // there is a special case for the JDT Comment Nodes
2921
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3 ✔
2922
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5 ✔
2923
                } else {
2924
                        node = node.getRoot();
3 ✔
2925
                }
2926

2927
                fa = new IndexedFileAnchor();
4 ✔
2928
                fa.setStartPos(beg);
4 ✔
2929
                fa.setEndPos(end);
4 ✔
2930

2931
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6 ✔
2932

2933
                return fa;
2 ✔
2934
        }
2935

2936
        /**
2937
         * Creates or recovers the Famix Class for "Object".
2938
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2939
         *
2940
         * @return a Famix class for "Object"
2941
         */
2942
        public Class ensureFamixClassObject() {
2943
        // 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...
2944
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5 ✔
2945

2946
        for (Class entity : objects) {
10 ✔
2947
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2948
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 ✔
2949
                    return entity;
2 ✔
2950
                }
2951
        }
1 ✔
2952

2953
        Class fmx = createFamixEntity(Class.class, "Object");
6 ✔
2954
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
2955
                return fmx;
2 ✔
2956
        }
2957

2958
        /***
2959
         * We treat array types as parametrized types Array<T>.
2960
         * This keeps the meta-model simple: a single way to model different concepts.
2961
         * @return
2962
         */
2963
        public ParametricClass ensureParametricArrayClass() {
2964
                
2965
                Collection<ParametricClass> arrayClasses = getEntityByName(ParametricClass.class, "Array");
5 ✔
2966
                
2967
                for (ParametricClass entity : arrayClasses) {
10 ✔
2968
            //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2969
            if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 !
2970
                return entity;
2 ✔
2971
            }
2972
                }
×
2973
                
2974
                //Create the parametric class
2975
                ParametricClass arrayClass = createFamixEntity(ParametricClass.class, "Array"); 
6 ✔
2976

2977
                //And now add the type parameter
2978
                TypeParameter fmxParam = this.ensureFamixTypeParameter(null, "T", arrayClass);
6 ✔
2979
                fmxParam.setGenericEntity(arrayClass);
3 ✔
2980
                fmxParam.setIsStub(true);
4 ✔
2981
                
2982
                //And the class is in java.lang
2983
                arrayClass.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
2984
                
2985
                return arrayClass;
2 ✔
2986
        }
2987

2988
        /**
2989
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2990
         */
2991
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2992
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
2993
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9 ✔
2994

2995
                if (fmx != null) {
2 !
2996
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7 ✔
2997
                }
2998

2999
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5 !
3000
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
3001
                }
3002

3003
                return fmx;
2 ✔
3004
        }
3005

3006
        public Class getFamixMetaClass(ITypeBinding bnd) {
3007
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
3008
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8 ✔
3009
        }
3010

3011
        /**
3012
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
3013
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
3014
         * JDT does not create a binding for these classes, so we create a stub one here.
3015
         *
3016
         * @return a Famix class
3017
         */
3018
        public Class ensureFamixClassArray() {
3019
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
3020
                if (fmx != null) {
×
3021
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
×
3022
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
3023

3024
                        // may be not needed anymore now that we use modifiers
3025
                        /*fmx.setIsAbstract(Boolean.FALSE);
3026
                        fmx.setIsFinal(Boolean.FALSE);
3027
                        fmx.setIsInterface(Boolean.FALSE); 
3028
                        fmx.setIsPrivate(Boolean.FALSE);
3029
                        fmx.setIsProtected(Boolean.FALSE);*/
3030
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
3031
                }
3032

3033
                return fmx;
×
3034
        }
3035

3036
        public String removeLastPartOfPackageName(String qualifiedName) {
3037
                String ret;
3038
                int last = qualifiedName.lastIndexOf('.');
4 ✔
3039
                if (last > 0) {
2 ✔
3040
                        // recursively creating the parent
3041
                        ret = qualifiedName.substring(0, last);
6 ✔
3042
                }
3043
                else {
3044
                        ret = "";
2 ✔
3045
                }
3046

3047
                return ret;
2 ✔
3048
        }
3049

3050
        /** Generates the list of parameters for a method signature
3051
         * @return a string
3052
         */
3053
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
3054
                boolean first = true;
2 ✔
3055
                String sig = "";
2 ✔
3056

3057
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17 ✔
3058
                        if (first) {
2 ✔
3059
                                sig = parBnd.getName();
3 ✔
3060
                                first = false;
3 ✔
3061
                        }
3062
                        else {
3063
                                sig += "," + parBnd.getName();
5 ✔
3064
                        }
3065
                }
3066
                return sig;
2 ✔
3067
        }
3068

3069
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
3070
                boolean first = true;
2 ✔
3071
                String sig = "";
2 ✔
3072

3073
                for (String t : paramTypes) {
10 ✔
3074
                        if (first) {
2 ✔
3075
                                sig = t;
2 ✔
3076
                                first = false;
3 ✔
3077
                        }
3078
                        else {
3079
                                sig += "," + t;
4 ✔
3080
                        }
3081
                }
1 ✔
3082
                return sig;
2 ✔
3083
        }
3084

3085
        public String findTypeName(org.eclipse.jdt.core.dom.Type t) {
3086
                if (t == null) {
×
3087
                        return null;
×
3088
                }
3089

3090
                if (t.isPrimitiveType()) {
×
3091
                        return t.toString();
×
3092
                } else if (t.isSimpleType()) {
×
3093
                        String fullName = ((SimpleType) t).getName().getFullyQualifiedName();
×
3094
                        int i = fullName.lastIndexOf('.');
×
3095
                        if (i > 0) {
×
3096
                                return fullName.substring(i+1);
×
3097
                        }
3098
                        else {
3099
                                return fullName;
×
3100
                        }
3101
                } else if (t.isQualifiedType()) {
×
3102
                        return ((QualifiedType) t).getName().getIdentifier();
×
3103
                } else if (t.isArrayType()) {
×
3104
                        return findTypeName(((ArrayType) t).getElementType());
×
3105
                } else if (t.isParameterizedType()) {
×
3106
                        return findTypeName(((org.eclipse.jdt.core.dom.ParameterizedType) t).getType());
×
3107
                } else { // it is a WildCardType
3108
                        if (((org.eclipse.jdt.core.dom.WildcardType) t).isUpperBound()) {
×
3109
                                return findTypeName(((org.eclipse.jdt.core.dom.WildcardType) t).getBound());
×
3110
                        } else {
3111
                                return EntityDictionary.OBJECT_NAME;
×
3112
                        }
3113
                }
3114
        }
3115

3116
        /**
3117
         * Ensures the proper creation of a FamixType for JDT typ in the given context.
3118
         * Useful for parameterizedTypes, or classInstance.
3119
         *
3120
         * @param isClass we are sure that the type is actually a class
3121
         * @return a famix type or null
3122
         */
3123
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass) {
3124
                return this.referredType(typ, ctxt, isClass, /*isExcep*/false);
7 ✔
3125
        }
3126
        
3127
        /**
3128
         * Ensures the proper creation of a FamixType for JDT type in the given context.
3129
         * Useful for parameterizedTypes, or classInstance.
3130
         *
3131
         * @param isClass we are sure that the type is actually a class
3132
         * @return a famix type or null
3133
         */
3134
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass, boolean isException) {
3135
                if (typ == null) {
2 !
3136
                        return null;
×
3137
                } else if (typ.resolveBinding() != null) {
3 !
3138
                        return this.referredType(typ.resolveBinding(), ctxt);
7 ✔
3139
                }
3140
                // from here, we assume the owner is the context
3141
                else if (isClass && !isException) {
×
3142
                        return this.ensureFamixClass(null, findTypeName(typ), /*owner*/ctxt, /*isGeneric*/false,
×
3143
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3144
                } else if (isException) {
×
3145
                        // return ensure FamixException
3146
                        return this.ensureFamixException(null, findTypeName(typ), (ContainerEntity) /*owner*/ctxt, /*isGeneric*/false,
×
3147
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3148
                } else {
3149
                        while (typ.isArrayType()) {
×
3150
                                typ = ((ArrayType) typ).getElementType();
×
3151
                        }
3152

3153
                        if (typ.isPrimitiveType()) {
×
3154
                                return this.ensureFamixPrimitiveType(null, findTypeName(typ));
×
3155
                        } else {
3156
                                return this.ensureFamixType(null, findTypeName(typ), /*owner*/ctxt, /*container*/ctxt,
×
3157
                                                EntityDictionary.UNKNOWN_MODIFIERS);
3158
                        }
3159
                }
3160
        }
3161
        
3162
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt) {
3163
                return this.referredType(bnd, ctxt, 0);
6 ✔
3164
        }
3165
        
3166
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt, int extraDimensions) {
3167
                TType fmxTyp = null;
2 ✔
3168

3169
                if (bnd == null) {
2 ✔
3170
                        return null;
2 ✔
3171
                }
3172

3173
                String name;
3174
                //Three cases here:
3175
                // - the type binding knows it's an array
3176
                // - the binding is not declared as array, but it has dimensions > 0
3177
                // - the dimension is not in the type but in the variable declaration (thus extra)
3178
                if (bnd.isArray() || bnd.getDimensions() + extraDimensions > 0) {
8 ✔
3179
                        // We treat array types as parametrized types Array<T>.
3180
                        // This keeps the meta-model simple: a single way to model different concepts.
3181
                        return this.ensureParametricArrayClass();
3 ✔
3182
                }
3183
                name = bnd.getName();
3 ✔
3184

3185
                if ( bnd.isParameterizedType() ) {
3 ✔
3186
                        
3187
                        // remove type parameters from the name even for parameterized interfaces
3188
                        int i = name.indexOf('<');
4 ✔
3189
                        if (i > 0) {
2 ✔
3190
                                name = name.substring(0, i);
5 ✔
3191
                        }
3192

3193
                        ITypeBinding parameterizableBnd = bnd.getErasure();
3 ✔
3194
                        int modifiers = (parameterizableBnd != null) ? parameterizableBnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
6 !
3195
                        
3196
                        if(parameterizableBnd != null && parameterizableBnd.isInterface()) {
5 !
3197
                                fmxTyp = (ParametricInterface) this.ensureFamixInterface(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
10 ✔
3198
                        } else {
3199
                                fmxTyp = (ParametricClass) this.ensureFamixClass(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
9 ✔
3200
                        }
3201
                } else if ( (name != null) && name.equals("var") ) {
7 !
3202
                        fmxTyp = this.ensureFamixUniqEntity(org.moosetechnology.model.famix.famixjavaentities.Type.class, /*binding*/null, EntityDictionary.IMPLICIT_VAR_TYPE_NAME);        
×
3203
                } else {
3204
                        fmxTyp = this.ensureFamixType(bnd, name, /*owner*/null, (TWithTypes) ctxt, bnd.getModifiers());
10 ✔
3205
                }
3206

3207
                return fmxTyp;
2 ✔
3208
        }
3209

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

© 2026 Coveralls, Inc