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

moosetechnology / VerveineJ / 31681878039

13 Aug 2026 08:23AM UTC coverage: 52.892% (-0.1%) from 53.003%
31681878039

Pull #261

github

web-flow
Merge 9d863b1dd into 7953741d5
Pull Request #261: Strict mode should not generate spurious stubs

2045 of 4032 branches covered (50.72%)

Branch coverage included in aggregate %.

5 of 27 new or added lines in 5 files covered. (18.52%)

7 existing lines in 2 files now uncovered.

4520 of 8380 relevant lines covered (53.94%)

2.22 hits per line

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

75.3
/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.Exceptions.VerveineJStrictModeException;
54
import fr.inria.verveine.extractor.java.utils.ImplicitVarBinding;
55
import fr.inria.verveine.extractor.java.utils.Util;
56

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

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

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

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

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

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

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

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

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

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

150
        /**
151
         * Option: If true, create stubs without package into a "Missing" package
152
         */
153
        protected boolean useMissingPackage;
154

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

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

208
                for (Access acc : famixRepo.all(Access.class)) {
13 ✔
209
                        // for the Exception to be raised, the return value must be tested
210
                        try { if (acc.getIsWrite()) {}        }
4 ✔
211
                        catch (NullPointerException e) { acc.setIsWrite(Boolean.FALSE); }
5 ✔
212
                }
1 ✔
213
        }
1 ✔
214

215
        protected void mapEntityToName(String name, TNamedEntity ent) {
216
                
217
                Collection<TNamedEntity> l_ent = nameToEntity.get(name);
6 ✔
218
                if (l_ent == null) {
2 ✔
219
                        l_ent = new LinkedList<>();
4 ✔
220
                }
221
                l_ent.add(ent);
4 ✔
222
                nameToEntity.put(name, l_ent);
6 ✔
223
        }
1 ✔
224

225
        public void removeEntity( NamedEntity ent) {
226
                IBinding key;
227
                key = entityToKey.get(ent);
6 ✔
228
                if (key != null) {
2 ✔
229
                        entityToKey.remove(ent);
5 ✔
230
                        keyToEntity.remove(key);
5 ✔
231
                }
232

233
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7 ✔
234
                if (l_ent != null) {
2 ✔
235
                        l_ent.remove(ent);
4 ✔
236
                }
237

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

269
                return ret;
2 ✔
270
        }
271

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

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

304
        /**
305
         * Returns the key associated to a Famix Entity.
306
         * @param e -- the Named entity
307
         * @return the key associated to this entity or null if none
308
         */
309
        public IBinding getEntityKey(TNamedEntity e) {
310
                return entityToKey.get(e);
6 ✔
311
        }
312

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

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

340
                        mapEntityToName(name, fmx);
4 ✔
341
                        
342
                        // put new entity in Famix repository
343
                        famixRepoAdd((Entity) fmx);
4 ✔
344
                }
345

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

367
                if (bnd != null) {
2 ✔
368
                        fmx = getEntityByKey(bnd, fmxClass);
5 ✔
369
                        if (fmx != null) {
2 ✔
370
                                return fmx;
2 ✔
371
                        }
372
                }
373

374
                // else
375
                fmx = createFamixEntity(fmxClass, name);
5 ✔
376
                if ( (bnd != null) && (fmx != null) ) {
4 !
377
                        mapEntityToKey(bnd, fmx);
4 ✔
378
                }
379
                
380
                return fmx;
2 ✔
381
        }
382

383
        /**
384
         * Adds an already created Entity to the Famix repository
385
         * Used mainly for non-NamedEntity, for example relationships
386
         * @param e -- the Famix entity to add to the repository
387
         */
388
        public void famixRepoAdd(Entity e) {
389
                this.famixRepo.add(e);
4 ✔
390
        }
1 ✔
391

392

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

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

438
        public AnnotationInstanceAttribute createFamixAnnotationInstanceAttribute(AnnotationTypeAttribute att, String value) {
439
                AnnotationInstanceAttribute fmx = null;
2 ✔
440
                if ( (att != null) && (value != null) ) {
4 !
441
                        fmx = new AnnotationInstanceAttribute();
4 ✔
442
                        fmx.setAnnotationTypeAttribute(att);
3 ✔
443
                        fmx.setValue(value);
3 ✔
444
                        this.famixRepo.add(fmx);
4 ✔
445
                }
446
                return fmx;
2 ✔
447
        }
448

449
        public AnnotationInstance addFamixAnnotationInstance(TWithAnnotationInstances fmx, AnnotationType annType, Collection<AnnotationInstanceAttribute> annAtts) {
450
                AnnotationInstance inst = null;
2 ✔
451
                if ( (fmx != null) && (annType != null) ) {
4 !
452
                        inst = new AnnotationInstance();
4 ✔
453
                        inst.setAnnotatedEntity(fmx);
3 ✔
454
                        inst.setAnnotationType(annType);
3 ✔
455
                        inst.addAttributes(annAtts);
3 ✔
456
                        this.famixRepo.add(inst);
4 ✔
457
                }
458
                return inst;
2 ✔
459
        }
460

461
        ///// ensure Famix Relationships /////
462

463
        /**
464
         * Returns a Famix Inheritance relationship between two Famix Classes creating it if needed
465
         * @param sup -- the super class
466
         * @param sub -- the sub class
467
         * @param prev -- previous inheritance relationship in the same context
468
         * @return the Inheritance relationship
469
         */
470
        public Inheritance ensureFamixInheritance(TWithInheritances sup, TWithInheritances sub, TAssociation prev, ITypeBinding supBnd) {
471
                if ( (sup == null) || (sub == null) ) {
4 !
472
                        return null;
×
473
                }
474

475
                // Does the inheritance already exist?
476
                for (TInheritance i : (sup).getSubInheritances()) {                        
11 ✔
477
                        if (i.getSubclass() == sub) {
4 ✔
478
                                return (Inheritance) i;
3 ✔
479
                        }
480
                }
1 ✔
481

482
                Inheritance inh;
483
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 ✔
484
                        inh = (ParametricInheritance)buildFamixParametricAssociation(new ParametricInheritance(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13 ✔
485
                } else {
486
                        inh = new Inheritance();
4 ✔
487
                }
488

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

510
                while (concreteIterator.hasNext() && genericIterator.hasNext()) {
6 ✔
511
                        TTypeArgument typeArgument = (TTypeArgument)ensureFamixType(concreteIterator.next());
7 ✔
512
                        TypeParameter typeParameter = (TypeParameter)ensureFamixType(genericIterator.next());
7 ✔
513

514
                        Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
515
                        association.addConcretization(concretization);
3 ✔
516
                }
1 ✔
517

518
                return association;
2 ✔
519
        }
520

521
        /**
522
         * Returns a Famix Concretization relationship between a Concrete Type and a ParameterType
523
         * @param typeArgument -- the concrete type
524
         * @param typeParameter -- the generic type parameter
525
         * @return the Concretization relationship
526
         */
527
        public Concretization ensureFamixConcretization(TTypeArgument typeArgument, TypeParameter typeParameter ) {
528
                if ( (typeArgument == null) || (typeParameter == null) ) {
4 !
529
                        return null;
×
530
                }
531

532
                Concretization concretization = new Concretization();
4 ✔
533
                concretization.setTypeArgument(typeArgument);
3 ✔
534
                concretization.setTypeParameter(typeParameter);
3 ✔
535

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

552
                for (TImplementation imp : myInterface.getImplementations()) {
11 ✔
553
                        if (imp.getImplementingClass() == implementingClass) {
4 ✔
554
                                return (Implementation) imp;
3 ✔
555
                        }
556
                }
1 ✔
557
                
558
                Implementation implementation;
559
                if (supBnd != null && supBnd.isParameterizedType()) { // Needs checks and tests.
5 !
560
                        implementation = (ParametricImplementation)buildFamixParametricAssociation(new ParametricImplementation(), supBnd.getErasure().getTypeParameters(), supBnd.getTypeArguments());
13 ✔
561
                } else {
562
                        implementation = new Implementation();
4 ✔
563
                }
564

565
                implementation.setImplementingClass(implementingClass);
3 ✔
566
                implementation.setMyInterface(myInterface);
3 ✔
567
                chainPrevNext(prev, implementation);
4 ✔
568
                famixRepoAdd(implementation);
3 ✔
569
                return implementation;
2 ✔
570
        }
571

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

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

606
                if (prev == null) {
2 ✔
607
                        for (TReference existingRef : src.getOutgoingReferences()) {
7 !
608
                                if (existingRef.getReferredEntity() == tgt) {
×
609
                                        return (Reference) existingRef;
×
610
                                }
611
                        }
×
612
                }
613

614
                if (referredTypeBnd != null) {
2 ✔
615
                        if (referredTypeBnd.isParameterizedType()) {
3 ✔
616
                                ref = (ParametricReference)buildFamixParametricAssociation(new ParametricReference(), referredTypeBnd.getErasure().getTypeParameters(), referredTypeBnd.getTypeArguments());
13 ✔
617
                        } else if (referredTypeBnd.isArray()) {
3 ✔
618
                                ref = new ParametricReference();
4 ✔
619
                        
620
                                TTypeArgument typeArgument  = (TTypeArgument)ensureFamixType(referredTypeBnd.getElementType());
6 ✔
621
                                TypeParameter typeParameter = (TypeParameter) ((TParametricEntity)tgt).getTypeParameters().iterator().next();
7 ✔
622

623
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
624
                                ((ParametricReference)ref).addConcretization(concretization);
4 ✔
625
                        }
626
                }
627

628
                if (ref == null){
2 ✔
629
                        ref = new Reference();
4 ✔
630
                }
631

632
                ref.setReferredEntity(tgt);
3 ✔
633
                ref.setReferencer(src);
3 ✔
634
                chainPrevNext(prev,ref);
4 ✔
635
                famixRepoAdd(ref);
3 ✔
636

637
                return ref;
2 ✔
638
        }
639

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

662
                invocation.setReceiver(receiver);
3 ✔
663
                invocation.setSender(tMethod);
3 ✔
664
                invocation.setSignature((signature == null) ? invoked.getSignature() : signature);
5 !
665
                invocation.addCandidates(invoked);
3 ✔
666
                chainPrevNext(prev,invocation);
4 ✔
667
                famixRepoAdd(invocation);
3 ✔
668
                
669
                return invocation;
2 ✔
670
        }
671

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

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

714
        /**
715
         * Returns a Famix CaughtException between a method and an Exception that is caught
716
         * @param meth -- the method catching the exception
717
         * @param excep -- the exception caught
718
         * @return the CaughtException
719
         */
720
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
721
                if ( (meth == null) || (excep == null) ) {
4 !
722
                        return null;
×
723
                }
724
                meth.getCaughtExceptions().add(excep);
5 ✔
725
                return excep;
2 ✔
726
        }
727

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

744

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

766
                                Concretization concretization = ensureFamixConcretization(typeArgument, typeParameter);
5 ✔
767
                                ((ParametricEntityTyping)typing).addConcretization(concretization);
4 ✔
768
                        }
769
                }
770

771
                // If we did not set a typing because not parameterized nor array, set a default one
772
                if (typing == null) {
2 ✔
773
                        typing = new EntityTyping();
4 ✔
774
                }
775
                
776
                typing.setTypedEntity(typedEntity);
3 ✔
777
                typing.setDeclaredType(declaredType);
3 ✔
778
                famixRepoAdd(typing);
3 ✔
779
                
780
                return typing;
2 ✔
781
        }
782

783

784
        ///// Special Case: ImplicitVariables /////
785

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

819
                return ret;
×
820
        }
821

822
        ///// Special Case: "Uniq" Entities /////
823

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

861
                return fmx;
2 ✔
862
        }
863

864
        /**
865
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
866
         *
867
         * @return a Famix class
868
         * @throws IllegalStateException if strict mod is activated and we try to generate a stub
869
         */
870
        public Class ensureFamixClassStubOwner() {
871

872
                // when strict mode is activated, we do not create stub container
873
                if (this.options != null && this.options.isStrict()) {
3 !
NEW
874
                        throw new VerveineJStrictModeException("Strict mode: We can't create stubs when strict mod is activated");
×
875
                }
876

877
                Class fmx = ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7 ✔
878
                if (fmx != null) {
2 !
879
                        /*if the option `useMissingPackage` is activated, we put all the stubs with unknown packages in a package `Missing*/
880
                        if(this.useMissingPackage) {
3 ✔
881
                                fmx.setTypeContainer(ensureFamixPackageMissing());
5 ✔
882
                        }
883
                        /*otherwise we put them in the default package*/
884
                        else {
885
                                fmx.setTypeContainer( ensureFamixPackageDefault());
4 ✔
886
                        }
887
                }
888
                ensureFamixInheritance(ensureFamixClassObject(), fmx, /* prev */null, null);
8 ✔
889

890
                return fmx;
2 ✔
891
        }
892

893
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
894
                if (ctxt == null) {
×
895
                        return null;
×
896
                }
897
                
898
                for (TType candidate : ctxt.getTypes()) {
×
899
                        if (candidate.getName().equals(name) ) {
×
900
                                return (Type) candidate;
×
901
                        }
902
                }
×
903
                
904
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
905
        }
906

907
        /**
908
         * Returns a Famix Package associated with its IPackageBinding and/or fully qualified name.
909
         * The Entity is created if it does not exist.
910
         * We assume that Namespaces must be uniq for a given name
911
         * Also creates or recovers recusively it's parent namespaces.<br>
912
         * At least one of <b>bnd</b> and <b>name</b> must be non null.
913
         *
914
         * @param bnd  -- the JDT Binding that may be used as a uniq key to recover this namespace
915
         * @param name -- fully qualified name of the namespace (e.g. 'java.lang')
916
         * @return the Famix Namespace found or created. May return null in case of a Famix error
917
         */
918
        public Package ensureFamixPackage(IPackageBinding bnd, String name) {
919
                Package fmx;
920
                Package parent;
921

922
                if ((name == null) && (bnd != null)) {
4 !
923
                        name = bnd.getName();
3 ✔
924
                }
925

926
                if ((name == null) || name.equals("")) {
6 !
927
                        return ensureFamixPackageDefault();
3 ✔
928
                } else {
929
                        /* Note: Packages are created with their fully-qualified name to simplify recovering when we don't have a binding
930
                         * (for example when creating parent packages of a package we have a binding for).
931
                         * Because the preferred solution in Moose is to give their simple names to packages, they must be post-processed when
932
                         * all is said and done. */
933
                        fmx = ensureFamixUniqEntity(Package.class, bnd, name);
7 ✔
934
                        String parentName = removeLastPartOfPackageName(name);
4 ✔
935
                        if (parentName.length() > 0) {
3 ✔
936
                                parent = ensureFamixPackage(null, parentName);
5 ✔
937
                                // set the parentscope relationship
938
                                if ((parent != null) && (fmx != null) && (fmx.getParentPackage() == null)) {
7 !
939
                                        parent.addChildEntities(fmx);
3 ✔
940
                                }
941
                        }
942
                }
943

944
                return fmx;
2 ✔
945
        }
946

947
        /**
948
         * Creates or recovers a default Famix Package.
949
         * Because this package does not really exist, it has no binding.
950
         *
951
         * @return a Famix Namespace
952
         */
953
        public Package ensureFamixPackageDefault() {
954
        return ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7 ✔
955
        }
956
        
957
        /**
958
         * Returns an artificial Package to contain stubs with an unknown package.
959
         * Always returns the same package. Create it lazily if not existing.
960
         * @return a Famix Namespace
961
         */
962
        public Package ensureFamixPackageMissing( ) {
963
                return ensureFamixUniqEntity(Package.class, null, MISSING_PCKG_NAME);
7 ✔
964
        }
965

966
        /**
967
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
968
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
969
         *
970
         * @param bnd -- a potential binding for the "java.lang" package
971
         * @return a Famix Namespace for "java.lang"
972
         */
973
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
974

975
        return this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5 ✔
976
        }
977

978
        /**
979
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
980
         */
981
        public Package getFamixPackageDefault() {
982
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5 ✔
983
                if (l.size() > 0) {
3 !
984
                        return l.iterator().next();
5 ✔
985
                } else {
986
                        return null;
×
987
                }
988
        }
989

990
        /**
991
         * Returns a Famix Type with the given <b>name</b>, creating it if it does not exist yet.
992
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public, not Interface
993
         * @param bnd -- binding for the type to create
994
         * @param name of the type
995
         * @param owner of the type
996
         * @param ctxt -- context of use of the type
997
         */
998
        public Type ensureFamixType(ITypeBinding bnd, String name, TWithTypes owner, TWithTypes ctxt, int modifiers) {
999
                
1000
                Type fmx;
1001

1002
                if (bnd == null) {
2 !
1003
                        if (name == null) {
×
1004
                                return null;
×
1005
                        }
1006
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
1007
                        if (fmx != null) {
×
1008
                                return fmx;
×
1009
                        }
1010

1011
                        if ((owner instanceof TParametricEntity)) {
×
1012
                                return this.ensureFamixTypeParameter(null, name, owner);
×
1013
                        }
1014
                        else {
1015
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1016
                                fmx.setTypeContainer(owner);
×
1017
                                return fmx;
×
1018
                        }
1019
                }
1020

1021
                // bnd != null
1022

1023
                fmx = (Type) getEntityByKey(bnd);
5 ✔
1024
                if (fmx != null) {
2 ✔
1025
                        return fmx;
2 ✔
1026
                }
1027

1028
                if (bnd.isArray()) {
3 !
1029
                        bnd = bnd.getElementType();
×
1030
                }
1031

1032
                if (bnd.isPrimitive()) {
3 ✔
1033
                        return this.ensureFamixPrimitiveType(bnd, name);
5 ✔
1034
                }
1035

1036
                if (bnd.isEnum()) {
3 !
1037
                        return this.ensureFamixEnum(bnd, name, owner);
×
1038
                }
1039
 
1040
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9 ✔
1041
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10 ✔
1042
                }
1043

1044
                if (bnd.isCapture()) {
3 ✔
1045
                        if (bnd.getErasure().isInterface()) {
4 !
1046
                                return this.ensureFamixInterface(bnd.getErasure(), name, owner, /*isGeneric*/true, modifiers);
9 ✔
1047
                        }
1048
                        else {
1049
                                return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
×
1050
                        }
1051
                }
1052

1053
                if (bnd.isAnnotation()) {
3 ✔
1054
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
7 ✔
1055
                }
1056

1057
                if (bnd.isInterface()) {
3 ✔
1058
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19 ✔
1059
                }
1060

1061
                if (isThrowable(bnd)) {
4 ✔
1062
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8 ✔
1063
                }
1064
                if (bnd.isClass()) {
3 ✔
1065
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20 !
1066
                }
1067
                if(bnd.isWildcardType()) {
3 ✔
1068
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8 ✔
1069
                }
1070

1071
                //otherwise (none of the above)
1072

1073
                if (name == null) {
2 ✔
1074
                        name = bnd.getName();
3 ✔
1075
                }
1076

1077
                if (owner == null) {
2 !
1078
                        owner = (TWithTypes) this.ensureOwner(bnd);
5 ✔
1079
                }
1080

1081
                if (bnd.isTypeVariable() ) {
3 !
1082
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6 ✔
1083
                        return fmx;
2 ✔
1084
                }
1085

1086
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1087
                fmx.setTypeContainer(owner);
×
1088
                return fmx;
×
1089
        }
1090

1091
        public Type ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1092
        int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
6 !
1093
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8 ✔
1094
        }
1095
        
1096
        public Type ensureFamixType(ITypeBinding bnd) {
1097
                return ensureFamixType(bnd, /*ctxt*/null);
5 ✔
1098
        }
1099

1100
        public boolean isThrowable(ITypeBinding bnd) {
1101
                if (bnd == null) {
2 !
1102
                        return false;
×
1103
                }
1104
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5 ✔
1105
                        return true;
2 ✔
1106
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5 ✔
1107
                        return false;
2 ✔
1108
                }
1109
                else {
1110
                        return isThrowable(bnd.getSuperclass());
5 ✔
1111
                }
1112
        }
1113

1114
        /**
1115
         * Returns a Famix Class associated with the ITypeBinding.
1116
         * The Entity is created if it does not exist.
1117
         * @param name -- the name of the Famix Class (MUST NOT be null, but this is not checked)
1118
         * @param owner -- package defining the class (should not be null, but it will work if it is)
1119
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1120
         */
1121
        @SuppressWarnings("deprecation")
1122
        public Class ensureFamixClass(ITypeBinding bnd, String name, TNamedEntity owner, boolean isGeneric, int modifiers) {
1123
                Class fmx;
1124

1125
                // --------------- some special cases
1126
                if (bnd != null) {
2 ✔
1127
                        if (bnd.isArray()) {
3 !
1128
                                bnd = bnd.getElementType();
×
1129
                        }
1130

1131
                        // for inner classes defined in generics !!! For others should not change anything
1132
                        bnd = bnd.getErasure();
3 ✔
1133
                }
1134

1135
                // ---------------- to avoid useless computations if we can
1136
                fmx = getEntityByKey(bnd, Class.class);
6 ✔
1137
                if (fmx != null) {
2 ✔
1138
                        return fmx;
2 ✔
1139
                }
1140

1141
                // --------------- name
1142
                if (name == null) {
2 ✔
1143
                        if (bnd == null) {
2 !
1144
                                return null;  // not much we can do
×
1145
                        } else if (!bnd.isAnonymous()) {
3 !
1146
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1147
                        } else { // anonymous class
1148
                                if (bnd.getSuperclass() != null) {
×
1149
                                        name = bnd.getSuperclass().getName();
×
1150
                                }
1151
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1152
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1153
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1154
                                                name = bnd.getInterfaces()[0].getName();
×
1155
                                        }
1156
                                        else {
1157
                                                name = "???";
×
1158
                                        }
1159
                                }
1160
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1161
                        }
1162
                }
1163

1164
        // If we have java.lang.Object we should ensure we create this class
1165
        if (bnd != null && bnd.getQualifiedName().equals("java.lang.Object")) {
7 ✔
1166
                        return ensureFamixClassObject();
3 ✔
1167
                }
1168

1169
                // --------------- owner
1170
                if (owner == null) {
2 ✔
1171
                        if (bnd != null) {
2 ✔
1172
                                owner = ensureOwner(bnd);
4 ✔
1173
                        }
1174
                        /*                                owner = ensureFamixPackageDefault();
1175
                        } else {*/
1176
                }
1177

1178
                // --------------- recover from name ?
1179
                if (owner != null) {
2 ✔
1180
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13 ✔
1181
                                if (matchAndMapClass(bnd, name, owner, candidate)) {
7 ✔
1182
                                        fmx = candidate;
2 ✔
1183
                                        break;
1 ✔
1184
                                }
1185
                        }
1 ✔
1186
                }
1187

1188
                // ---------------- create
1189
                if (fmx == null) {
2 ✔
1190
                        if (isGeneric) {
2 ✔
1191
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8 ✔
1192
                        }
1193
                        else {
1194
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7 ✔
1195
                                fmx.setTypeContainer((TWithTypes)owner);
4 ✔
1196
                        }
1197
                }
1198

1199
                // ---------------- modifiers and super-classes
1200
                if (fmx!=null) {
2 !
1201
                        // we just created it, or it was not bound so we make sure it has the right information in it
1202
                        if (bnd != null) {
2 ✔
1203
                                setClassModifiers(fmx, bnd.getDeclaredModifiers(), (TWithTypes) owner);
7 ✔
1204
                        }
1205

1206
                        TAssociation lastAssoc = null;
2 ✔
1207

1208
                        if (bnd != null) {
2 ✔
1209
                                ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1210
                                if (supbnd != null) {
2 ✔
1211
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1212
                                }
1213
                                else {
1214
                                        lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
8 ✔
1215
                                }
1216
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7 ✔
1217
                        }
1218
                }
1219

1220
                return fmx;
2 ✔
1221
        }
1222

1223
        /**
1224
         * Returns a Famix Exception associated with the ITypeBinding.
1225
         * The Entity is created if it does not exist.
1226
         * @param name -- the name of the Famix Exception
1227
         * @param owner -- type defining the Exception (should not be null, but it will work if it is) 
1228
         *
1229
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
1230
         */
1231
        public <T extends TWithTypes & TNamedEntity> Exception ensureFamixException(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1232
                Exception fmx;
1233

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

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

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

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

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

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

1290
                // ---------------- create
1291
                if (fmx == null) {
2 !
1292
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7 ✔
1293
                        fmx.setTypeContainer(owner);
3 ✔
1294
                }
1295

1296
        // we just created it or it was not bound, so we make sure it has the right information in it
1297
        TAssociation lastAssoc = null;
2 ✔
1298
        if (bnd != null) {
2 ✔
1299
            ITypeBinding supbnd = bnd.getSuperclass();
3 ✔
1300
            if (supbnd != null) {
2 !
1301
                lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11 ✔
1302
            }
1303
            else {
1304
                lastAssoc = ensureFamixInheritance(ensureFamixClassObject(), fmx, lastAssoc, null);
×
1305
            }
1306
            ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6 ✔
1307
        }
1308

1309
        return fmx;
2 ✔
1310
        }
1311

1312
        /**
1313
         * Returns a FAMIX Interface with the given <b>name</b>, creating it if it does not exist yet.
1314
         * @param name -- the name of the FAMIX Method
1315
         * @param owner -- type defining the method (should not be null, but it will work if it is) 
1316
         * @return the FAMIX Class or null in case of a FAMIX error
1317
         */
1318
        public <T extends TWithTypes & TNamedEntity> Interface ensureFamixInterface(ITypeBinding bnd, String name, TWithTypes owner, boolean isGeneric, int modifiers) {
1319
                Interface fmx;
1320

1321
                // --------------- some special cases
1322
                if (bnd != null) {
2 !
1323
                        if (bnd.isArray()) {
3 !
1324
                                bnd = bnd.getElementType();
×
1325
                        }
1326

1327
                        // for inner classes defined in generics !!! For others should not change anything
1328
                        bnd = bnd.getErasure();
3 ✔
1329
                }
1330

1331
                // ---------------- to avoid useless computations if we can
1332
                fmx = getEntityByKey(bnd, Interface.class);
6 ✔
1333
                if (fmx != null) {
2 ✔
1334
                        return fmx;
2 ✔
1335
                }
1336

1337
                // --------------- name
1338
                if (name == null) {
2 ✔
1339
                        if (bnd == null) {
2 !
1340
                                return null;  // not much we can do
×
1341
                        } else if (!bnd.isAnonymous()) {
3 !
1342
                                name = bnd.getErasure().getName();  // for generics, will give the "core" type name, for normal type, won't change anything
5 ✔
1343
                        } else { // anonymous class
1344
                                if (bnd.getSuperclass() != null) {
×
1345
                                        name = bnd.getSuperclass().getName();
×
1346
                                }
1347
                                if ((name == null) || name.equals(OBJECT_NAME)) {
×
1348
                                        ITypeBinding[] intfcs = bnd.getInterfaces();
×
1349
                                        if ((intfcs != null) && (intfcs.length > 0)) {
×
1350
                                                name = bnd.getInterfaces()[0].getName();
×
1351
                                        }
1352
                                        else {
1353
                                                name = "???";
×
1354
                                        }
1355
                                }
1356
                                name = ANONYMOUS_NAME_PREFIX + "(" + name + ")";
×
1357
                        }
1358
                }
1359

1360
                // --------------- owner
1361
                if (owner == null) {
2 ✔
1362
                        if (bnd == null) {
2 !
1363
                                owner = ensureFamixPackageDefault();
×
1364
                        } else {
1365
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1366
                        }
1367
                }
1368

1369
                // --------------- recover from name ?
1370
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13 ✔
1371
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8 ✔
1372
                                fmx = candidate;
2 ✔
1373
                                break;
1 ✔
1374
                        }
1375
                }
1 ✔
1376

1377
                // ---------------- create
1378
                if (fmx == null) {
2 ✔
1379
                        if (isGeneric) {
2 ✔
1380
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7 ✔
1381
                        }
1382
                        else {
1383
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7 ✔
1384
                                fmx.setTypeContainer(owner);
3 ✔
1385
                        }
1386
                }
1387

1388
                // ---------------- modifiers and "super interfaces"
1389
                if (fmx!=null) {
2 !
1390
                        // we just created it or it was not bound, so we make sure it has the right information in it
1391
                        if (bnd != null) {
2 !
1392
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5 ✔
1393
                        }
1394
                        TAssociation lastAssociation = null;
2 ✔
1395
                        if (bnd != null) {
2 !
1396
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6 ✔
1397
                        }
1398
                }
1399
                return fmx;
2 ✔
1400
        }
1401

1402
        /**
1403
         * "Converts" (if needed) a TTYpe entity to be a TThrowable. Might involve removing the existing entity, recreating a new one and migrating
1404
         * all the relationship of the former to the later
1405
         */
1406
        public TThrowable asException(TType fmxType) {
1407
                if (fmxType instanceof Exception) {
3 ✔
1408
                        return (Exception) fmxType;
3 ✔
1409
                }
1410
                if(fmxType instanceof TypeParameter) {
3 ✔
1411
                        return (TypeParameter) fmxType;
3 ✔
1412
                }
1413

1414
                Exception fmxException = null;
2 ✔
1415
                IBinding key;
1416

1417
                try {
1418
                        key = entityToKey.get(fmxType);
6 ✔
1419

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

1424
                        TWithTypes owner = fmxType.getTypeContainer();
3 ✔
1425
                        fmxType.setTypeContainer(null);
3 ✔
1426
                        fmxException = ensureFamixException((ITypeBinding) key, fmxType.getName(), owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
10 ✔
1427

1428
                        fmxException.addMethods( new ArrayList<>( ((TWithMethods)fmxType).getMethods() ) );
8 ✔
1429
                        if (fmxType instanceof TWithAttributes) {
3 !
1430
                                fmxException.addAttributes( new ArrayList<>( ((TWithAttributes)fmxType).getAttributes() ) );
8 ✔
1431
                        }
1432

1433
                        if (fmxType instanceof TWithInheritances) {
3 !
1434
                                fmxException.addSuperInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSuperInheritances() ) );
8 ✔
1435
                                fmxException.addSubInheritances( new ArrayList<>( ((TWithInheritances) fmxType).getSubInheritances() ) );
8 ✔
1436
                        }
1437
                        fmxException.setComments(new ArrayList<>( ((TWithComments) fmxType).getComments() ));
8 ✔
1438
                        fmxException.setSourceAnchor(fmxType.getSourceAnchor());
4 ✔
1439
                        fmxException.addIncomingTypings( new ArrayList<>( fmxType.getIncomingTypings() ) );
7 ✔
1440
                        fmxException.addAnnotationInstances( new ArrayList<>( ((NamedEntity)fmxType).getAnnotationInstances() ) );
8 ✔
1441
                        fmxException.addIncomingReferences( new ArrayList<>( fmxType.getIncomingReferences() ) );
7 ✔
1442
                        fmxException.setIsStub(fmxType.getIsStub());
4 ✔
1443
                        fmxException.addTypes( new ArrayList<>( ((ContainerEntity) fmxType).getTypes() ) );
8 ✔
1444
                }
1445
                catch( ConcurrentModificationException e) {
×
1446
                        e.printStackTrace();
×
1447
                }
1 ✔
1448

1449
                return fmxException;
2 ✔
1450
        }
1451

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

1459
        /**
1460
         * helper method, we know the type exists, ensureFamixInterface will recover it
1461
         */
1462
        public Interface getFamixInterface(ITypeBinding bnd, String name, ContainerEntity owner) {
1463
                return ensureFamixInterface(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1464
        }
1465

1466
        /**
1467
         * helper method, we know the type exists, ensureFamixInterface will recover it
1468
         */
1469
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1470
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8 ✔
1471
        }
1472

1473
        /**
1474
         * Ensures a famix entity for the owner of a binding.<br>
1475
         * This owner can be a method, a class or a namespace
1476
         * @param bnd -- binding for the owned entity
1477
         * @return a famix entity for the owner
1478
         */
1479
        private TNamedEntity ensureOwner(ITypeBinding bnd) {
1480
                TNamedEntity owner;
1481
                IMethodBinding parentMtd = bnd.getDeclaringMethod();
3 ✔
1482
                if (parentMtd != null) {
2 ✔
1483
                        owner = this.ensureFamixMethod(parentMtd);  // cast needed to desambiguate the call
5 ✔
1484
                }
1485
                else {
1486
                        ITypeBinding parentClass = bnd.getDeclaringClass();
3 ✔
1487
                        if (parentClass != null) {
2 ✔
1488
                owner = this.ensureFamixType(parentClass);
5 ✔
1489
            }
1490
                        else {
1491
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1492
                                if (parentPckg != null) {
2 !
1493
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1494
                                } else {
1495
                                        owner = this.ensureFamixPackageDefault();
×
1496
                                }
1497
                        }
1498
                }
1499
                return owner;
2 ✔
1500
        }
1501

1502

1503
        /**
1504
         * Returns a FAMIX PrimitiveType with the given <b>name</b>, creating it if it does not exist yet
1505
         * We assume that PrimitiveType must be uniq for a given name
1506
         * @param name -- the name of the FAMIX PrimitiveType
1507
         * @return the FAMIX PrimitiveType or null in case of a FAMIX error
1508
         */
1509
        public PrimitiveType ensureFamixPrimitiveType(ITypeBinding bnd, String name) {
1510
                if (name == null) {
2 ✔
1511
                        if (bnd == null) {
2 !
1512
                                return null;
×
1513
                        } else {
1514
                                name = bnd.getName();
3 ✔
1515
                        }
1516
                }
1517
                return ensureFamixUniqEntity(PrimitiveType.class, bnd, name);
7 ✔
1518
        }
1519

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

1523
                // --------------- to avoid useless computations if we can
1524
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5 ✔
1525
                if (fmx != null) {
2 ✔
1526
                        return fmx;
2 ✔
1527
                }
1528

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

1539
                // --------------- owner
1540
                if (owner == null) {
2 ✔
1541
                        if (bnd == null) {
2 !
1542
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1543
                        } else {
1544
                                owner = (TWithTypes) ensureOwner(bnd);
5 ✔
1545
                        }
1546
                }
1547

1548
                // --------------- recover from name ?
1549
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9 !
1550
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1551
                                fmx = candidate;
×
1552
                                break;
×
1553
                        }
1554
                }
×
1555

1556
                if (fmx == null) {
2 !
1557
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7 ✔
1558
                        fmx.setTypeContainer(owner);
3 ✔
1559
                }
1560

1561
                if (bnd != null) {
2 !
1562
                        setVisibility(fmx, bnd.getModifiers(), owner);
6 ✔
1563
                }
1564

1565
                return fmx;
2 ✔
1566
        }
1567

1568
        /**
1569
         * helper method, we know the type exists, ensureFamixEnum will recover it
1570
         */
1571
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1572
                return ensureFamixEnum(bnd, name, owner);
6 ✔
1573
        }
1574

1575
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1576
                EnumValue fmx;
1577

1578
                // --------------- to avoid useless computations if we can
1579
                fmx = (EnumValue)getEntityByKey(bnd);
5 ✔
1580
                if (fmx != null) {
2 ✔
1581
                        return fmx;
2 ✔
1582
                }
1583

1584
                // --------------- name
1585
                if (name == null) {
2 !
1586
                        if (bnd == null) {
×
1587
                                return null;
×
1588
                        }
1589
                        else {
1590
                                name = bnd.getName();
×
1591
                        }
1592
                }
1593

1594
                // --------------- owner
1595
                if (owner == null) {
2 ✔
1596
                        if (bnd == null) {
2 !
1597
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1598
                        }
1599
                        else {
1600
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7 ✔
1601
                        }
1602
                }
1603

1604
                // --------------- recover from name ?
1605
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9 !
1606
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1607
                                fmx = candidate;
×
1608
                                break;
×
1609
                        }
1610
                }
×
1611
                if (fmx == null) {
2 !
1612
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7 ✔
1613
                        fmx.setParentEnum(owner);
3 ✔
1614
                }
1615

1616
        fmx.setParentEnum(owner);
3 ✔
1617

1618
        return fmx;
2 ✔
1619
        }
1620

1621
    /**
1622
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1623
         */
1624
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1625
                AnnotationType fmx;
1626

1627
                // --------------- to avoid useless computations if we can
1628
                fmx = (AnnotationType)getEntityByKey(bnd);
5 ✔
1629
                if (fmx != null) {
2 ✔
1630
                        return fmx;
2 ✔
1631
                }
1632

1633
                // --------------- name
1634
                if (name == null) {
2 ✔
1635
                        if (bnd == null) {
2 !
1636
                                return null;
×
1637
                        }
1638
                        else {
1639
                                name = bnd.getName();
3 ✔
1640
                        }
1641
                }
1642

1643
                // --------------- owner
1644
                if (owner == null) {
2 ✔
1645
                        if (bnd == null) {
2 !
1646
                                owner = ensureFamixPackageDefault();
×
1647
                        }
1648
                        else {
1649
                                IPackageBinding parentPckg = bnd.getPackage();
3 ✔
1650
                                if (parentPckg != null) {
2 !
1651
                                        owner = this.ensureFamixPackage(parentPckg, null);
6 ✔
1652
                                } else {
1653
                                        owner = this.ensureFamixPackageDefault();
×
1654
                                }
1655
                        }
1656
                }
1657

1658
                // --------------- recover from name ?
1659
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13 ✔
1660
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7 !
1661
                                fmx = candidate;
2 ✔
1662
                                break;
1 ✔
1663
                        }
1664
                }
×
1665

1666
                // --------------- create
1667
                if (fmx == null) {
2 ✔
1668
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7 ✔
1669
                        fmx.setAnnotationTypesContainer(owner);
3 ✔
1670
                }
1671

1672
                if (bnd != null) {
2 !
1673
                        // Not supported in Famix
1674

1675
                        // setVisibility(fmx, bnd.getModifiers());
1676
                }
1677

1678
                return fmx;
2 ✔
1679
        }
1680

1681
        /**
1682
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1683
         */
1684
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1685
                return ensureFamixAnnotationType(bnd, name, owner);
6 ✔
1686
        }
1687

1688
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1689
                AnnotationTypeAttribute fmx = null;
2 ✔
1690

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

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

1707
                // --------------- owner
1708
                if (owner == null) {
2 !
1709
                        if (bnd == null) {
×
1710
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1711
                        }
1712
                        else {
1713
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1714
                                if (parentType != null) {
×
1715
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1716
                                }
1717
                                else  {
1718
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1719
                                }
1720
                        }
1721
                }
1722

1723
                // --------------- recover from name ?
1724
                for (AnnotationTypeAttribute candidate : getEntityByName(AnnotationTypeAttribute.class, name) ) {
13 ✔
1725
                        // JDT treats annotation type attributes as methods ...
1726
                        // checkAndMapMethod wants a signature as 2nd argument so we add empty param list
1727
                        if ( (bnd != null) && matchAndMapMethod(bnd, name+"()", null, owner, candidate) ) {
11 !
1728
                                fmx = candidate;
×
1729
                                break;
×
1730
                        }
1731
                        // if the binding is null, the annotationTypeAttribute migth have been created
1732
                        else if ( (bnd == null) && matchAndMapVariable(null, name, owner, candidate)) {
2 !
1733
                                fmx = candidate;
×
1734
                                break;
×
1735
                        }
1736
                }
1 ✔
1737

1738
                if (fmx == null) {
2 !
1739
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7 ✔
1740
                        fmx.setParentType(owner);
3 ✔
1741
                }
1742

1743
                if (bnd != null) {
2 !
1744
                        // Not suopp
1745

1746
                        // setVisibility(fmx, bnd.getModifiers());
1747
                }
1748

1749
                return fmx;
2 ✔
1750
        }
1751

1752
        /**
1753
         * helper method, we know the attribute exists, ensureFamixAnnotationTypeAttribute will recover it
1754
         */
1755
        public AnnotationTypeAttribute getFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1756
                return ensureFamixAnnotationTypeAttribute( bnd, name, owner);
6 ✔
1757
        }
1758
        
1759
        
1760
        /**
1761
         * Returns a FAMIX Wildcard with its bounds
1762
         * @param bnd
1763
         * @param name
1764
         * @param owner
1765
         * @return
1766
         */
1767
        public Wildcard ensureFamixWildcardType(ITypeBinding bnd, String name, TParametricEntity owner, TWithTypes ctxt) {
1768
                Wildcard fmx = this.ensureFamixEntity(Wildcard.class, bnd, bnd.getName());
8 ✔
1769
                if(bnd.getBound() != null) {
3 ✔
1770
                        Type bound = this.ensureFamixType(bnd.getBound());
5 ✔
1771
                        if(bnd.isUpperbound()) {
3 ✔
1772
                                fmx.setUpperBound(bound);
3 ✔
1773
                                bound.addUpperBoundedWildcards(fmx);
4 ✔
1774
                        }else{
1775
                                fmx.setLowerBound(bound);
3 ✔
1776
                                bound.addLowerBoundedWildcards(fmx);
3 ✔
1777
                        }
1778
                }
1779
                return fmx;
2 ✔
1780
        }
1781

1782
        /**
1783
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1784
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1785
         * @param name -- the name of the Famix TypeParameter
1786
         * @return the Famix TypeParameter or null in case of a Famix error
1787
         */
1788
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1789
                TypeParameter fmx;
1790

1791
                // --------------- to avoid useless computations if we can
1792
                fmx = (TypeParameter)getEntityByKey(bnd);
5 ✔
1793
                if (fmx != null) {
2 ✔
1794
                        return fmx;
2 ✔
1795
                }
1796

1797
                // --------------- name
1798
                if (name == null) {
2 ✔
1799
                        if (bnd == null) {
2 !
1800
                                return null;
×
1801
                        }
1802
                        else {
1803
                                name = bnd.getName();
3 ✔
1804
                        }
1805
                }
1806

1807
                // --------------- owner
1808
                if (owner == null && bnd != null) {
2 !
1809
            if (bnd.getDeclaringClass() != null) {
×
1810
                owner = this.ensureFamixType(bnd.getDeclaringClass());
×
1811
            } else if(bnd.getDeclaringMethod() != null) {
×
1812
                owner = this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1813
            }
1814
                }
1815

1816
                // --------------- recover from name ?
1817
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13 ✔
1818
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8 ✔
1819
                                fmx = (TypeParameter) candidate;
3 ✔
1820
                                break;
1 ✔
1821
                        }
1822
                }
1 ✔
1823

1824
                // --------------- create
1825
                if (fmx == null) {
2 ✔
1826
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7 ✔
1827
                        if(bnd != null && bnd.getSuperclass() != null) {
5 !
1828
                                Type upperBound = ensureFamixType(bnd.getSuperclass());
5 ✔
1829
                                fmx.setUpperBound(upperBound);
3 ✔
1830
                        }
1831
                        if(bnd != null) {
2 ✔
1832
                for (ITypeBinding intbnd : bnd.getInterfaces()) {
17 ✔
1833
                    Type upperBound = ensureFamixType(intbnd);
4 ✔
1834
                    fmx.setUpperBound(upperBound);
3 ✔
1835
                }
1836
            }
1837
                        fmx.setTypeContainer(owner);
3 ✔
1838
                }
1839

1840
                return fmx;
2 ✔
1841
        }
1842

1843
        /**
1844
         * Checks whether the existing unmapped Famix Namespace matches the binding.
1845
         * Checks that the candidate has the same name as the JDT bound package, and checks recursively that owners also match.
1846
         *
1847
         * @param bnd       -- a JDT binding that we are trying to match to the candidate
1848
         * @param name      of the package
1849
         * @param owner     of the package
1850
         * @param candidate -- a Famix Entity
1851
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1852
         */
1853
        private boolean matchAndMapPackage(IPackageBinding bnd, String name, Package owner, NamedEntity candidate) {
1854
                if (!(candidate instanceof Package)) {
3 !
1855
                        return false;
×
1856
                }
1857

1858
                // check whether bnd and candidate are already bound
1859
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1860
                if (res == CheckResult.MATCH) {
3 ✔
1861
                        return true;
2 ✔
1862
                } else if (res == CheckResult.FAIL) {
3 ✔
1863
                        return false;
2 ✔
1864
                }
1865

1866
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
1867
                        return false;
2 ✔
1868
                }
1869

1870
                // names match, not need to look at owner because names of Namespaces are their fully qualified name
1871
                conditionalMapToKey(bnd, candidate);
4 ✔
1872
                return true;
2 ✔
1873
        }
1874

1875
        /**
1876
         * Checks whether the existing unmapped Famix Type matches the binding.
1877
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1878
         * We also check that the actual class of the candidate matches (can be a sub-class of FamixType).
1879
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1880
         * @param name of the type
1881
         * @param owner of the type
1882
         * @param candidate -- a Famix NamedEntity (Class, Type, PrimitiveType, Enum, AnnotationType)
1883
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1884
         */
1885
        private <T extends TWithTypes & TNamedEntity> boolean matchAndMapType(ITypeBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
1886
                if (! (candidate instanceof Type) ) {
3 !
1887
                        return false;
×
1888
                }
1889

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

1899
                if ( (bnd != null) && (bnd.isArray()) ) {
5 ✔
1900
                                bnd = bnd.getElementType();
3 ✔
1901
                }
1902

1903
                // checking names
1904
                if ( (bnd != null) && (bnd.isParameterizedType() || bnd.isRawType()) ) {
8 !
1905
                        name = bnd.getErasure().getName();
5 ✔
1906
                }
1907
                else if (bnd != null) {
2 ✔
1908
                        name = bnd.getName();
3 ✔
1909
                }
1910
                // else name = name
1911
                if (checkNameMatch(null, name, candidate) == CheckResult.FAIL) {
7 ✔
1912
                        return false;
2 ✔
1913
                }
1914

1915
                // special case of primitive types
1916
                if (candidate instanceof PrimitiveType) {
3 !
1917
                        if ( (bnd != null) && bnd.isPrimitive() ) {
×
1918
                                // names are equal so it's OK
1919
                                conditionalMapToKey(bnd, candidate);
×
1920
                                return true;
×
1921
                        }
1922
                        else if ( (bnd == null) && (owner == null) ) {
×
1923
                                return true;
×
1924
                        }
1925
                }
1926

1927
                // check owners without bnd
1928
                if (bnd == null) {
2 ✔
1929
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1930
                }
1931

1932
                // check owners with bnd
1933
                // type is an annotation
1934
                if (bnd.isAnnotation() && (candidate instanceof AnnotationType)) {
6 !
1935
                        if (matchAndMapPackage(bnd.getPackage(), owner.getName(), (Package) Util.getOwner(owner), Util.getOwner(candidate))) {
13 !
1936
                                conditionalMapToKey(bnd, candidate);
4 ✔
1937
                                return true;
2 ✔
1938
                        } else {
1939
                                return false;
×
1940
                        }
1941
                }
1942

1943
                // check owners with bnd
1944
                // type is a Parameterized type
1945
                if ((bnd.isParameterizedType() || bnd.isRawType()) && (candidate instanceof ParametricClass)) {
9 !
1946
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1947
                }
1948

1949
                // check owners with bnd
1950
                // type is an Enum
1951
                if (bnd.isEnum() && (candidate instanceof Enum)) {
3 !
1952
                        return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
×
1953
                }
1954

1955
                // check owners with bnd
1956
                // type is something elae (a class or interface)
1957
                // Annotation are interfaces too, so we should check this one after isAnnotation
1958
                if ( bnd.isClass()) {
3 !
1959
                        return matchAndMapClass(bnd, name, owner, (Type) candidate);
×
1960
                }
1961

1962
                if(bnd.isInterface()) {
3 ✔
1963
                        return matchAndMapInterface(bnd, name, owner, (Type) candidate);
8 ✔
1964
                }
1965

1966
                return false;
2 ✔
1967
        }
1968

1969
        /**
1970
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
1971
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
1972
         * @param bnd -- a JDT binding that we are trying to match to the candidate
1973
         * @param name of the class
1974
         * @param owner of the class
1975
         * @param candidate -- a Famix Entity
1976
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
1977
         */
1978
        private boolean matchAndMapClass(ITypeBinding bnd, String name, TNamedEntity owner, TType candidate) {
1979
                if (!(candidate instanceof Class)) {
3 !
1980
                        return false;
×
1981
                }
1982

1983
                // check whether bnd and candidate are already bound
1984
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
1985
                if (res == CheckResult.MATCH) {
3 ✔
1986
                        return true;
2 ✔
1987
                } else if (res == CheckResult.FAIL) {
3 ✔
1988
                        return false;
2 ✔
1989
                }
1990

1991
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
1992
                        return false;
×
1993
                }
1994

1995
                // checking owner
1996
                return matchAndMapTypeOwner(bnd, owner, (Type) candidate);
7 ✔
1997
        }
1998

1999
        /**
2000
         * Checks whether the existing unmapped Famix Class (or Interface) matches the binding.
2001
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2002
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2003
         * @param name of the class
2004
         * @param owner of the class
2005
         * @param candidate -- a Famix Entity
2006
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2007
         */
2008
        private boolean matchAndMapInterface(ITypeBinding bnd, String name, TNamedEntity owner, Type candidate) {
2009
                if (!(candidate instanceof Interface)) {
3 !
2010
                        return false;
×
2011
                }
2012

2013
                // check whether bnd and candidate are already bound
2014
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
2015
                if (res == CheckResult.MATCH) {
3 ✔
2016
                        return true;
2 ✔
2017
                } else if (res == CheckResult.FAIL) {
3 ✔
2018
                        return false;
2 ✔
2019
                }
2020

2021
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
2022
                        return false;
2 ✔
2023
                }
2024

2025
                // checking owner
2026
                return matchAndMapTypeOwner(bnd, owner, candidate);
6 ✔
2027
        }
2028

2029
        /**
2030
         * Checks whether the existing unmapped Famix "Method" matches the binding.
2031
         * Checks that the candidate has the same name and same signature as the JDT bound method, and checks recursively that owners also match.
2032
         * Note that AnnotationTypeAttribute are treated as methods by JDT, so they are checked here.
2033
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2034
         * @param sig -- signature of the method
2035
         * @param retTyp -- return type of the method
2036
         * @param owner of the method
2037
         * @param candidate -- a Famix Entity (regular Method or AnnotationTypeAttribute)
2038
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2039
         */
2040
        private  boolean matchAndMapMethod(IMethodBinding bnd, String sig, TType retTyp, TNamedEntity owner, NamedEntity candidate) {
2041
                if (! (candidate instanceof Method) ) {
3 ✔
2042
                        return false;
2 ✔
2043
                }
2044

2045
                // check whether bnd and candidate are already bound
2046
                CheckResult res = checkKeyMatch(bnd, candidate);
5 ✔
2047
                if (res == CheckResult.MATCH) {
3 ✔
2048
                        return true;
2 ✔
2049
                }
2050
                else if (res == CheckResult.FAIL) {
3 ✔
2051
                        return false;
2 ✔
2052
                }
2053

2054
                // checking names
2055
                String name = (sig != null) ? sig.substring(0, sig.indexOf('(')) : null;
10 !
2056
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 ✔
2057
                        return false;
2 ✔
2058
                }
2059

2060
                // for methods, the name is not enough, we must test the signature also
2061
                // but not for AnnotationTypeAttribute
2062

2063
                        if (bnd != null) {
2 ✔
2064
                                sig = bnd.getName() + "(" + signatureParamsFromBinding(bnd) + ")";
7 ✔
2065
                        }
2066
                        if (! ((Method) candidate).getSignature().equals(sig)) {
6 ✔
2067
                                return false;
2 ✔
2068
                        }
2069

2070
                        // and still for method, must also check the return type
2071
                        if (bnd != null) {
2 ✔
2072
                                if (isConstructorBinding(bnd)) {
4 !
2073
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
×
2074
                                                return false;
×
2075
                                        }
2076
                                        // else OK for now
2077
                                }
2078
                                else { // not a constructor
2079
                                        if ( ((Method) candidate).getDeclaredType() == null ) {
4 !
2080
                                                return false;
×
2081
                                        }
2082
                                        else if (! matchAndMapType(bnd.getReturnType(), null, null, ((Method) candidate).getDeclaredType()) ) {
10 ✔
2083
                                                return false;
2 ✔
2084
                                        }
2085
                                        // else OK for now
2086
                                }
2087
                        }
2088
                        else {  // bnd == null
2089
                                if (retTyp == null) { // similar to (bnd.isConstructor())
2 !
2090
                                        if ( ((Method) candidate).getDeclaredType() != null ) {
4 ✔
2091
                                                return false;
2 ✔
2092
                                        }
2093
                                        // else OK for now
2094
                                } else { // (ret != null)  i.e. not a constructor
2095
                                        if (((Method) candidate).getDeclaredType() == null) {
×
2096
                                                return false;
×
2097
                                        } else if (!matchAndMapType(null, retTyp.getName(), Util.getOwner(retTyp), (NamedEntity) ((Method) candidate).getDeclaredType())) {
×
2098
                                                return false;
×
2099
                                        }
2100
                                        // else OK for now
2101
                                }
2102
                        }
2103

2104

2105
                // check owner
2106
                if (matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, Util.getOwner(candidate)) == CheckResult.MATCH) {
13 ✔
2107
                        conditionalMapToKey(bnd, candidate);
4 ✔
2108
                        return true;
2 ✔
2109
                } else {
2110
                        return false;
2 ✔
2111
                }
2112
        }
2113

2114
        /** testing that a method binding is for a constructor
2115
         * There is a special case for "diamond constructors" (eg: <code>new HashSet<>()</code>)
2116
         */
2117
        protected boolean isConstructorBinding(IMethodBinding bnd) {
2118
                if (bnd.isConstructor()) {
3 ✔
2119
                        return true;
2 ✔
2120
                }
2121
                if ( bnd.getName().equals("<factory>") ) {
5 ✔
2122
                        return true;
2 ✔
2123
                }
2124
                return false;
2 ✔
2125
        }
2126

2127
        /**
2128
         * Checks whether the candidate (an existing unmapped Famix "Variable" like Attribute, Parameter, ...) matches the binding.
2129
         * Checks that the candidate has the same name as the JDT bound variable, and checks recursively that owners also match.
2130
         * The Famix candidate is a NamedEntity and not a StructuralEntity to allow dealing with Famix EnumValue that JDT treats as variables
2131
         * @param bnd -- a JDT binding that we are trying to match to the candidate
2132
         * @param name of the variable
2133
         * @param owner of the variable
2134
         * @param candidate -- a Famix Entity (a StructuralEntity or an EnumValue)
2135
         * @return whether the binding matches the candidate (if <b>true</b>, the mapping is recorded)
2136
         */
2137
        private boolean matchAndMapVariable(IVariableBinding bnd, String name, TNamedEntity owner, TNamedEntity candidate) {
2138
                if (!(candidate instanceof TStructuralEntity)) {
3 !
2139
                        return false;
×
2140
                }
2141

2142
                // check whether bnd and candidate are already bound
2143
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5 ✔
2144
                if (keyMatch == CheckResult.MATCH) {
3 !
2145
                        return true;
×
2146
                } else if (keyMatch == CheckResult.FAIL) {
3 ✔
2147
                        return false;
2 ✔
2148
                }
2149

2150
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7 !
2151
                        return false;
×
2152
                }
2153

2154
                // check owner
2155
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3 ✔
2156

2157
                // local variable or parameter ?
2158
                // owner is a Method? (for example in case of an anonymous class)
2159
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11 ✔
2160
                if (res == CheckResult.FAIL) {
3 ✔
2161
                        return false;
2 ✔
2162
                } else if (res == CheckResult.MATCH) {
3 !
2163
                        conditionalMapToKey(bnd, candidate);
×
2164
                        return true;
×
2165
                }
2166

2167
                // check owner
2168
                // <anArray>.length field?
2169
                if (name.equals("length")) {
4 !
2170
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2171
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2172
                        if (isArrayLengthField) {
×
2173
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2174
                                        conditionalMapToKey(bnd, candidate);
×
2175
                                        return true;
×
2176
                                }
2177
                                else {
2178
                                        return false;
×
2179
                                }
2180
                        }
2181
                }
2182

2183
                // check owner
2184
                // "normal" field?
2185
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2186
                if (res == CheckResult.MATCH) {
3 !
2187
                        conditionalMapToKey(bnd, candidate);
4 ✔
2188
                        return true;
2 ✔
2189
                }
2190
                return false;
×
2191
        }
2192

2193
        /**
2194
         * Checks whether the existing unmapped Famix Type's parent (or owner) matches the binding's owner.
2195
         * Checks that the candidate has the same name as the JDT bound type, and checks recursively that owners also match.
2196
         * @param bnd -- a JDT binding whose owner we are trying to match to the candidate's owner
2197
         * @param owner -- the owner of the type
2198
         * @param candidate -- a Famix Entity
2199
         * @return whether we found a match (if <b>true</b>, the mapping is recorded)
2200
         */
2201
        private boolean matchAndMapTypeOwner(ITypeBinding bnd, TNamedEntity owner, Type candidate) {
2202
                ContainerEntity candidateOwner = Util.getOwner(candidate);
4 ✔
2203

2204
                // owner is a Method? (for example in case of an anonymous class)
2205
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11 ✔
2206
                if (res == CheckResult.MATCH) {
3 !
2207
                        conditionalMapToKey(bnd, candidate);
×
2208
                        return true;
×
2209
                } else if (res == CheckResult.FAIL) {
3 !
2210
                        return false;
×
2211
                }
2212

2213
                // owner is a class ?
2214
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11 ✔
2215
                if (res == CheckResult.MATCH) {
3 ✔
2216
                        conditionalMapToKey(bnd, candidate);
4 ✔
2217
                        return true;
2 ✔
2218
                }
2219
                else if (res == CheckResult.FAIL) {
3 ✔
2220
                        return false;
2 ✔
2221
                }
2222

2223
                // owner must be a package
2224
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12 ✔
2225
                        conditionalMapToKey(bnd, candidate);
4 ✔
2226
                        return true;
2 ✔
2227
                }
2228
                return false;
2 ✔
2229
        }
2230

2231
        /**
2232
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2233
         * @param methBnd
2234
         * @param owner
2235
         * @param candidateOwner
2236
         * @return a {@link CheckResult}
2237
         */
2238
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2239
                if ((methBnd != null) || (owner instanceof Method)) {
5 !
2240
                        if (!(candidateOwner instanceof Method)) {
3 !
2241
                                return CheckResult.FAIL;
×
2242
                        }
2243

2244
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7 !
2245
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7 !
2246
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8 !
2247

2248
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9 !
2249
                                return CheckResult.MATCH;
×
2250
                        } else {
2251
                                return CheckResult.FAIL;
2 ✔
2252
                        }
2253
                }
2254
                return CheckResult.UNDECIDED;
2 ✔
2255
        }
2256

2257
        /**
2258
         * @param typBnd
2259
         * @param owner
2260
         * @param candidateOwner
2261
         * @return a {@link CheckResult}
2262
         */
2263
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2264
                if ((typBnd != null) || (owner instanceof Type)) {
5 ✔
2265
                        if (!(candidateOwner instanceof Type)) {
3 ✔
2266
                                return CheckResult.FAIL;
2 ✔
2267
                        }
2268

2269
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6 !
2270
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2271

2272
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7 ✔
2273
                                return CheckResult.MATCH;
2 ✔
2274
                        } else {
2275
                                return CheckResult.FAIL;
2 ✔
2276
                        }
2277
                }
2278
                return CheckResult.UNDECIDED;
2 ✔
2279
        }
2280

2281
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2282
                if ((pckgBnd != null) || (owner instanceof Package)) {
5 !
2283
                        if (!(candidateOwner instanceof Package)) {
3 !
2284
                                return CheckResult.FAIL;
×
2285
                        }
2286

2287
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7 !
2288
                        String ownerName = (owner != null) ? owner.getName() : null;
6 !
2289

2290
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7 ✔
2291
                                return CheckResult.MATCH;
2 ✔
2292
                        } else {
2293
                                return CheckResult.FAIL;
2 ✔
2294
                        }
2295
                }
2296
                return CheckResult.UNDECIDED;
×
2297
        }
2298

2299
        /**
2300
         * Checks whether the name and the candidate matches the name of the entity (given either by 'bnd' or 'name')<br>
2301
         * 'name' and 'bnd' cannot be null together
2302
         * @param bnd -- binding associated with the entity may be null
2303
         * @param name -- name of the entity may be null
2304
         * @param candidate
2305
         * @return true if names match, false if not
2306
         */
2307
        private CheckResult checkNameMatch(IBinding bnd, String name, TNamedEntity candidate) {
2308
                if ( (bnd != null) && (! bnd.getName().equals(candidate.getName())) ) {
8 ✔
2309
                        return CheckResult.FAIL;
2 ✔
2310
                }
2311
                else if ( (bnd == null) && (name != null) && (! name.equals(candidate.getName())) ) {
9 !
2312
                        return CheckResult.FAIL;
2 ✔
2313
                }
2314
                else {
2315
                        return CheckResult.MATCH;
2 ✔
2316
                }
2317
        }
2318

2319
        /**
2320
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2321
         * @param key
2322
         * @param candidate
2323
         * @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>
2324
         */
2325
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2326
                if (key == null) {
2 ✔
2327
                        return CheckResult.UNDECIDED;
2 ✔
2328
                }
2329

2330
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5 ✔
2331
                if (bound == candidate) {
3 ✔
2332
                        return CheckResult.MATCH;
2 ✔
2333
                }
2334
                else if (bound != null) {
2 ✔
2335
                        return CheckResult.FAIL;
2 ✔
2336
                }
2337
                else if (getEntityKey(candidate) != null) {
4 ✔
2338
                        //we check if the both bindings are linked to the same entity
2339
                        IBinding candidateBinding = getEntityKey(candidate);
4 ✔
2340
                        if(candidateBinding.getKey().equals(key.getKey())) {
6 ✔
2341
                                return CheckResult.MATCH;
2 ✔
2342
                        }
2343
                        
2344
                        //if candidate is a stub, we accept multiple recovery binding
2345
                        //this code will be upgraded with the possibility to add manually code to entities
2346
                        if (candidate instanceof TCanBeStub && ((TCanBeStub) candidate).getIsStub()) {
8 !
2347
                                return CheckResult.UNDECIDED;
2 ✔
2348
                        }
2349
      
2350
                        return CheckResult.FAIL;
2 ✔
2351
                }
2352
                else {
2353
                        return CheckResult.UNDECIDED;
2 ✔
2354
                }
2355
        }
2356

2357
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2358
                if (bnd != null) {
2 ✔
2359
                        mapEntityToKey(bnd, ent);
4 ✔
2360
                }
2361
        }
1 ✔
2362

2363
        public Method ensureFamixMethod(IMethodBinding bnd) {
2364
                return ensureFamixMethod(
8 ✔
2365
                                bnd,
2366
                                /*name*/null,
2367
                                /*paramsType*/null,
2368
                                /*returnType*/null,
2369
                                /*owner*/null,
2370
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6 ✔
2371
        }
2372

2373
        /**
2374
         * Returns a Famix Method associated with the IMethodBinding.
2375
         * The Entity is created if it does not exist.
2376
         * @param name -- the name of the Famix Method (MUST NOT be null, but this is not checked)
2377
         * @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)
2378
         * @param owner -- type defining the method (should not be null, but it will work if it is)
2379
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2380
         */
2381
        public Method ensureFamixMethod(IMethodBinding bnd, String name, Collection<String> paramTypes, TType ret, TWithMethods owner, int modifiers) {
2382
                Method fmx;
2383
                String signature;
2384
                boolean delayedRetTyp;
2385

2386
                // --------------- to avoid useless computations if we can
2387
                fmx = (Method)getEntityByKey(bnd);
5 ✔
2388
                if (fmx != null) {
2 ✔
2389
                        return fmx;
2 ✔
2390
                }
2391

2392
                // --------------- name
2393
                if (name == null) {
2 ✔
2394
                        if (bnd == null) {
2 ✔
2395
                                return null;
2 ✔
2396
                        }
2397
                        else {
2398
                                name = bnd.getName();
3 ✔
2399
                        }
2400
                }
2401

2402
                // --------------- signature
2403
                signature = name + "(";
3 ✔
2404
                 if (bnd != null) {
2 ✔
2405
                    signature += signatureParamsFromBinding(bnd);
7 ✔
2406
                }
2407
        else if (paramTypes != null) {
2 !
2408
                        signature += signatureParamsFromStringCollection(paramTypes);
7 ✔
2409
                }
2410
                else {
2411
                        signature += "???";
×
2412
                }
2413
                signature += ")";
3 ✔
2414

2415
                // --------------- return type
2416
                delayedRetTyp = false;
2 ✔
2417
                ITypeBinding retTypBnd = null;
2 ✔
2418
                if (ret == null) {
2 !
2419
                        if (bnd != null) {
2 ✔
2420
                // must create the return type
2421
                // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2422
                // we need T to create the method and the method to create T ...
2423
                // so we need to test the situation and deal with it
2424
                retTypBnd = bnd.getReturnType();
3 ✔
2425
                if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9 ✔
2426
                    delayedRetTyp = true;
3 ✔
2427
                }
2428
                else {
2429
                        ret = this.referredType(retTypBnd, fmx);
5 ✔
2430
                }
2431
                        }
2432
                }
2433

2434
                // --------------- owner
2435
                if (owner == null) {
2 ✔
2436
                        if (bnd == null) {
2 ✔
2437
                                owner = ensureFamixClassStubOwner();
4 ✔
2438
                        }
2439
                        else {
2440
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4 ✔
2441
                                if (classBnd != null) {
2 !
2442
                                        owner = ensureFamixType(classBnd);
5 ✔
2443
                                }
2444
                                else {
2445
                                        owner = ensureFamixClassStubOwner();
×
2446
                                }
2447
                        }
2448
                }
2449

2450
                // --------------- recover from name ?
2451
                for (Method candidate : this.getEntityByName(Method.class, name)) {
13 ✔
2452
                        if (matchAndMapMethod(bnd, signature, ret, (TNamedEntity) owner, candidate)) {
9 ✔
2453
                                fmx = candidate;
2 ✔
2454
                                break;
1 ✔
2455
                        }
2456
                }
1 ✔
2457

2458
                if (fmx == null) {
2 ✔
2459
                        if(bnd != null && bnd.isGenericMethod() && !isConstructorBinding(bnd)) {
9 ✔
2460
                                fmx = ensureFamixEntity(ParametricMethod.class, bnd, name);
7 ✔
2461
                                for(ITypeBinding param: bnd.getTypeParameters()) {
18 ✔
2462
                                        TypeParameter fmxParam = this.ensureFamixTypeParameter(param, null, fmx);
6 ✔
2463
                                        fmxParam.setGenericEntity((ParametricMethod)fmx);
4 ✔
2464
                                }
2465
                        // Parameterized method binding = when the method is the target of an invocation.
2466
                        } else if (bnd != null && bnd.isParameterizedMethod()) {
5 ✔
2467
                                fmx = this.ensureFamixMethod(bnd.getMethodDeclaration());
6 ✔
2468
                        } else {
2469
                if (bnd != null && isConstructorBinding(bnd)) {
6 ✔
2470
                    fmx = ensureFamixEntity(Initializer.class, bnd, name);
8 ✔
2471
                } else {
2472
                    fmx = ensureFamixEntity(Method.class, bnd, name);
7 ✔
2473
                }
2474
            }
2475

2476
                        fmx.setSignature(signature);
3 ✔
2477
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
7 ✔
2478
                        ensureFamixEntityTyping(returnTypeBnd, fmx, ret);
6 ✔
2479
                        fmx.setParentType(owner);
3 ✔
2480
                }
2481

2482
                if (fmx != null) {
2 !
2483
                        setMethodModifiers(fmx, modifiers);
4 ✔
2484
                }
2485

2486
        //If it has the #default keywork, we mark it as default implementation
2487
        if (Modifier.isDefault(modifiers)) {
3 ✔
2488
            fmx.setKind(DEFAULT_IMPLEMENTATION_KIND_MARKER);
3 ✔
2489
        }
2490

2491
        if (delayedRetTyp) {
2 ✔
2492
                        int retTypModifiers = retTypBnd.getModifiers();
3 ✔
2493
                        ITypeBinding returnTypeBnd = bnd.getReturnType();
3 ✔
2494
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13 ✔
2495
                }
2496

2497
                return fmx;
2 ✔
2498
        }
2499

2500

2501
        /**
2502
         * Creates or recovers the initializer method containing the attribute initializations of a type.
2503
         * @param owner Type containing the initializer
2504
         * @param isStatic Modifier of the initializer. A type can have 2 initializers for attribute initialization: 1 static and 1 not.
2505
         * @param isInitializationBlock True if the entity is an initialization block. False for the artificial method containing all field initializations.
2506
         * @return the FamixInitializer
2507
         */
2508
        public Initializer ensureFamixInitializer(TWithMethods owner, Boolean isStatic, Boolean isInitializationBlock) {
2509
                Initializer fmx = null;
2 ✔
2510

2511
                if (owner != null) {
2 !
2512
                        Optional<TMethod> existingInitializer = owner.getMethods().stream()
6 ✔
2513
                                        .filter(meth ->
1 ✔
2514
                                                        ((Method) meth).getIsInitializer() &&
8 ✔
2515
                                                        ((Method) meth).getIsConstructor().equals(false) &&
7 ✔
2516
                                                        ((Method) meth).getIsClassSide().equals(isStatic) &&
6 ✔
2517
                                                        ((Initializer) meth).getIsInitializationBlock().equals(isInitializationBlock))
7 ✔
2518
                                        .findFirst();
2 ✔
2519
                        if (existingInitializer.isPresent()) {
3 ✔
2520
                                fmx = (Initializer) existingInitializer.get();
4 ✔
2521
                        }
2522
                }
2523

2524
                if (fmx == null) {
2 ✔
2525
                        fmx = createFamixEntity(Initializer.class, INIT_BLOCK_NAME);
6 ✔
2526
                        fmx.setSignature(INIT_BLOCK_NAME + "()" );
3 ✔
2527
                        fmx.setVisibility(MODIFIER_PRIVATE);
3 ✔
2528
                        fmx.setParentType(owner);
3 ✔
2529
                        fmx.setIsClassSide(isStatic);
3 ✔
2530
                        fmx.setIsInitializationBlock(isInitializationBlock);
3 ✔
2531
                }
2532

2533
                return fmx;
2 ✔
2534
        }
2535

2536

2537
        public Initializer ensureImplicitConstructor(IMethodBinding binding, TWithMethods owner, String name, Collection<String> parameterTypesNames) {
2538
                Initializer fmx = null;
2 ✔
2539

2540
                if (fmx == null) {
2 !
2541
                        int modifiers = (binding != null) ? binding.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
7 ✔
2542
                        if (binding == null) {
2 ✔
2543
                                // OK! Binding is null, this is the default constructor!!
2544
                                // It has no source code :)
2545
                                fmx = ensureFamixEntity(Initializer.class, null, name);
7 ✔
2546
                                fmx.setParentType(owner);
3 ✔
2547
                                fmx.setSignature(name + "()");                                
5 ✔
2548
                        } else {
2549
                                // But, if we have the binding, that means the constructor exists. Let's just go the normal way
2550
                                fmx = (Initializer) this.ensureFamixMethod(binding, name, parameterTypesNames, /*ret type*/null, owner, modifiers);
10 ✔
2551
                        }
2552
                }
2553

2554
                return fmx;
2 ✔
2555
        }
2556

2557
        /**
2558
         * Creates or recovers a stub Famix Method
2559
         * @param name of the method
2560
         * @return the Famix Method
2561
         * @throws IllegalStateException if strict mod is activated and we try to generate a stub
2562
         */
2563
        public Method ensureFamixStubMethod(String name) {
2564
                // // when strict mod is activated, we do not create stubs
NEW
2565
                if (this.options != null && this.options.isStrict()) {
×
NEW
2566
                        throw new VerveineJStrictModeException("Strict mode: We can't create the stub '" + name + "' when strict mod is activated");
×
2567
                }
NEW
2568
                return ensureFamixMethod(null, name, /* paramType */null, /* returnType */null, ensureFamixClassStubOwner(),/* modifiers */0);
×
2569
        }
2570

2571
        public void setAttributeModifiers(Attribute fmx, int mod) {
2572
                setCommonModifiers(fmx, mod, null);
5 ✔
2573
                fmx.setIsTransient(Modifier.isTransient(mod));
5 ✔
2574
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5 ✔
2575
        }
1 ✔
2576

2577
        public void setMethodModifiers(Method fmx, int mod) {
2578
                setCommonModifiers(fmx, mod, (TWithTypes) fmx.getParentType());
7 ✔
2579
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2580
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5 ✔
2581
        }
1 ✔
2582

2583
        public void setClassModifiers(Class fmx, int mod, TWithTypes owner) {
2584
                setCommonModifiers(fmx, mod, null);
5 ✔
2585
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5 ✔
2586
        }
1 ✔
2587

2588
        public void setInterfaceModifiers(Interface fmx, int mod) {
2589
                setCommonModifiers(fmx, mod, null);
5 ✔
2590
        }
1 ✔
2591

2592
        private void setCommonModifiers(Entity fmx, int mod, TWithTypes owner) {
2593
                setVisibility((THasVisibility)fmx, mod, owner);
6 ✔
2594
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6 ✔
2595
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6 ✔
2596
        }
1 ✔
2597

2598
        /**
2599
         * Sets the visibility of a FamixNamedEntity
2600
         *
2601
         * @param fmx -- the FamixNamedEntity
2602
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2603
         */
2604
        public void setVisibility(THasVisibility fmx, int mod, TWithTypes owner) {
2605
                if (Modifier.isPublic(mod)) {
3 ✔
2606
                        fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2607
                } else if (Modifier.isPrivate(mod)) {
3 ✔
2608
                        fmx.setVisibility(MODIFIER_PRIVATE);
4 ✔
2609
                } else if (Modifier.isProtected(mod)) {
3 ✔
2610
                        fmx.setVisibility(MODIFIER_PROTECTED);
4 ✔
2611
                } else {
2612
                        //Default visibility!
2613
                        //If we are in an interface, default visibility is public, otherwise package.
2614
                        if (owner instanceof Interface) {
3 ✔
2615
                                fmx.setVisibility(MODIFIER_PUBLIC);
4 ✔
2616
                        } else {
2617
                                fmx.setVisibility(MODIFIER_PACKAGE);
3 ✔
2618
                        }
2619
                }
2620
        }
1 ✔
2621

2622
        /**
2623
         * Returns a Famix Attribute associated with the IVariableBinding.
2624
         * The Entity is created if it does not exist.<br>
2625
         * @param name -- the name of the FAMIX Attribute (MUST NOT be null, but this is not checked)
2626
         * @param type -- Famix Type of the Attribute (should not be null, but it will work if it is)
2627
         * @param owner -- type defining the Attribute (should not be null, but it will work if it is)
2628
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2629
         */
2630
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, Type type, TWithAttributes owner) {
2631
                Attribute fmx;
2632

2633
                // --------------- to avoid useless computations if we can
2634
                fmx = (Attribute)getEntityByKey(bnd);
5 ✔
2635
                if (fmx != null) {
2 ✔
2636
                        return fmx;
2 ✔
2637
                }
2638

2639
                // --------------- name
2640
                if (name == null) {
2 !
2641
                        if (bnd == null) {
×
2642
                                return null;
×
2643
                        }
2644
                        else {
2645
                                name = bnd.getName();
×
2646
                        }
2647
                }
2648

2649
                // --------------- owner
2650
                if (owner == null) {
2 ✔
2651
                        if (bnd == null) {
2 !
2652
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2653
                        }
2654
                        else {
2655
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7 !
2656
                                        // Declaring class is the generic one if the class is parametric.
2657
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8 ✔
2658
                                } else {
2659
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2 ✔
2660
                                }
2661
                        }
2662
                }
2663

2664
                // --------------- recover from name ?
2665
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13 ✔
2666
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8 ✔
2667
                                fmx = candidate;
2 ✔
2668
                                break;
1 ✔
2669
                        }
2670
                }
1 ✔
2671

2672
                if (fmx == null) {
2 ✔
2673
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7 ✔
2674
                        fmx.setParentType( owner);
3 ✔
2675
                }
2676

2677
        fmx.setParentType(owner);
3 ✔
2678
        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7 ✔
2679
        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6 ✔
2680
        if (bnd != null) {
2 ✔
2681
            int mod = bnd.getModifiers();
3 ✔
2682
            setAttributeModifiers(fmx, mod);
4 ✔
2683
        }
2684

2685
        return fmx;
2 ✔
2686
        }
2687

2688
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2689
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2690
        }
2691

2692
        /**
2693
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2694
         */
2695
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2696
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7 ✔
2697
        }
2698

2699
        /**
2700
         * Returns a Famix Parameter associated with the IVariableBinding.
2701
         * The Entity is created if it does not exist.<br>
2702
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2703
         */
2704
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2705
                Parameter fmx = null;
2 ✔
2706

2707
                // --------------- to avoid useless computations if we can
2708
                try {
2709
                        fmx = (Parameter)getEntityByKey(bnd);
5 ✔
2710
                }catch(Throwable e) {
×
2711
                        e.printStackTrace();
×
2712
                }
1 ✔
2713
                if (fmx != null) {
2 ✔
2714
                        return fmx;
2 ✔
2715
                }
2716

2717
                // --------------- name
2718
                if (name == null) {
2 !
2719
                        if (bnd == null) {
×
2720
                                return null;
×
2721
                        }
2722
                        else {
2723
                                name = bnd.getName();
×
2724
                        }
2725
                }
2726

2727
                // --------------- owner
2728
                if (tMethod == null) {
2 !
2729
                        if (bnd == null) {
×
2730
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2731
                        }
2732
                        else {
2733
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2734
                        }
2735
                }
2736

2737
                // --------------- recover from name ?
2738
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13 ✔
2739
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7 !
2740
                                fmx = candidate;
×
2741
                                break;
×
2742
                        }
2743
                }
1 ✔
2744

2745
                if (fmx == null) {
2 !
2746
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7 ✔
2747
                }
2748

2749
                if (fmx != null) {
2 !
2750
                        fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2751
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5 !
2752
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6 ✔
2753
                }
2754

2755
                return fmx;
2 ✔
2756
        }
2757

2758
    /**
2759
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2760
         * The Entity is created if it does not exist.<br>
2761
         * @param name -- the name of the FAMIX LocalVariable
2762
         * @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
2763
         */
2764
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2765
                LocalVariable fmx;
2766

2767
                // --------------- to avoid useless computations if we can
2768
                fmx = (LocalVariable)getEntityByKey(bnd);
5 ✔
2769
                if (fmx != null) {
2 !
2770
                        return fmx;
×
2771
                }
2772

2773
                // --------------- name
2774
                if (name == null) {
2 !
2775
                        if (bnd == null) {
×
2776
                                return null;
×
2777
                        }
2778
                        else {
2779
                                name = bnd.getName();
×
2780
                        }
2781
                }
2782

2783
                // --------------- owner
2784
                if (owner == null) {
2 !
2785
                        if (bnd == null) {
×
2786
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2787
                        }
2788
                        else {
2789
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2790
                        }
2791
                }
2792

2793
                // --------------- recover from name ?
2794
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13 ✔
2795
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8 !
2796
                                fmx = candidate;
×
2797
                                break;
×
2798
                        }
2799
                }
1 ✔
2800

2801
                if (fmx == null) {
2 !
2802
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7 ✔
2803
                        fmx.setParentBehaviouralEntity(owner);
3 ✔
2804
                }
2805

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

2809
        return fmx;
2 ✔
2810
        }
2811

2812
    /**
2813
         * Returns a FAMIX ImplicitVariable with the given <b>name</b> ("self" or "super") and corresponding to the <b>type</b>.
2814
         * If this ImplicitVariable does not exist yet, it is created
2815
         * @param name -- the name of the FAMIX ImplicitVariable (should be Dictionary.SELF_NAME or Dictionary.SUPER_NAME)
2816
         * @param type -- the Famix Type for this ImplicitVariable (should not be null)
2817
         * @param tMethod -- the ContainerEntity where the implicit variable appears (should be a method inside <b>type</b>)
2818
         * @return the FAMIX ImplicitVariable or null in case of a FAMIX error
2819
         */
2820
        public ImplicitVariable ensureFamixImplicitVariable(IBinding key, String name, TType type, TMethod tMethod) {
2821
                ImplicitVariable fmx;
2822
                fmx = ensureFamixEntity(ImplicitVariable.class, key, name);
7 ✔
2823
                fmx.setParentBehaviouralEntity(tMethod);
3 ✔
2824
                return fmx;
2 ✔
2825
        }
2826

2827
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2828
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4 ✔
2829
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7 ✔
2830
        }
2831

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

2841
                if ( (jCmt != null) && (owner != null) ) {
4 !
2842
                        
2843
                        cmt = new Comment();
4 ✔
2844
                        addSourceAnchor(cmt, jCmt);
5 ✔
2845
                        famixRepoAdd(cmt);
3 ✔
2846
                        cmt.setCommentedEntity(owner);
3 ✔
2847
                }
2848

2849
                return cmt;
2 ✔
2850
        }
2851

2852
        /**
2853
         * Creates and returns a Famix Comment and associates it with an Entity
2854
         * @param jCmt -- the content (String) of the comment 
2855
         * @param owner -- the entity that is commented
2856
         * @param content -- the text of the comment
2857
         * @return the Famix Comment
2858
         */
2859
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2860
                Comment cmt = null;
2 ✔
2861

2862
                if ( (jCmt != null) && (owner != null) ) {
4 !
2863
                        cmt = new Comment();
4 ✔
2864
                        cmt.setContent(content );
3 ✔
2865
                        famixRepoAdd(cmt);
3 ✔
2866
                        cmt.setCommentedEntity(owner);
3 ✔
2867
                }
2868

2869
                return cmt;
2 ✔
2870
        }
2871

2872
        /**
2873
         * Adds location information to a Famix Entity.
2874
         * 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.
2875
         * This method also creates some basic links between the entity and others (e.g. declaring container, return type, ...)
2876
         * @param fmx -- Famix Entity to add the anchor to
2877
         * @param node -- JDT ASTNode, where the information is extracted
2878
         * @return the Famix SourceAnchor added to fmx. May be null in case of incorrect parameter ('fmx' or 'ast' == null)
2879
         */
2880
        public SourceAnchor addSourceAnchor(TSourceEntity fmx, ASTNode node) {
2881
                IndexedFileAnchor fa;
2882

2883
                fa = createIndexedFileAnchor(node);
4 ✔
2884
                if ((fmx != null) && (fa != null)) {
4 !
2885
                        fmx.setSourceAnchor(fa);
3 ✔
2886
                        famixRepoAdd(fa);
3 ✔
2887
                }
2888

2889
                return fa;
2 ✔
2890
        }
2891

2892
        /**
2893
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2894
         */
2895
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2896
                IndexedFileAnchor fa;
2897

2898
                fa = createIndexedFileAnchor(node);
4 ✔
2899
                if ((fmx != null) && (fa != null)) {
4 !
2900

2901
                        // may change the positions
2902
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4 ✔
2903
                        methodDeclarationModifiers.addAll(node.modifiers());
5 ✔
2904
                        if (node.getName() != null) {
3 !
2905
                                methodDeclarationModifiers.add(node.getName());
5 ✔
2906
                        }
2907
                        if (node.getReturnType2() != null) {
3 ✔
2908
                                methodDeclarationModifiers.add(node.getReturnType2());
5 ✔
2909
                        }
2910
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12 ✔
2911
                        int end = node.getStartPosition() + node.getLength();
6 ✔
2912

2913
                        fa.setStartPos(beg);
4 ✔
2914
                        fa.setEndPos(end);
4 ✔
2915

2916
                        fmx.setSourceAnchor(fa);
3 ✔
2917
                        famixRepoAdd(fa);
3 ✔
2918
                }
2919

2920
                return fa;
2 ✔
2921
        }
2922

2923
        /**
2924
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2925
         * Information returned in the form of an IndexedFileAnchor
2926
         */
2927
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2928
                IndexedFileAnchor fa;
2929
                
2930
                if (node == null) {
2 !
2931
                        return null;
×
2932
                }
2933

2934
                // position in source file
2935
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5 ✔
2936
                int end = beg + node.getLength() - 1;
7 ✔
2937

2938
                // find source Compilation Unit
2939
                // there is a special case for the JDT Comment Nodes
2940
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3 ✔
2941
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5 ✔
2942
                } else {
2943
                        node = node.getRoot();
3 ✔
2944
                }
2945

2946
                fa = new IndexedFileAnchor();
4 ✔
2947
                fa.setStartPos(beg);
4 ✔
2948
                fa.setEndPos(end);
4 ✔
2949

2950
                fa.setFileName((String) node.getProperty(SOURCE_FILENAME_PROPERTY));
6 ✔
2951

2952
                return fa;
2 ✔
2953
        }
2954

2955
        /**
2956
         * Creates or recovers the Famix Class for "Object".
2957
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2958
         *
2959
         * @return a Famix class for "Object"
2960
         */
2961
        public Class ensureFamixClassObject() {
2962
        // 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...
2963
        Collection<Class> objects = getEntityByName(Class.class, "Object");
5 ✔
2964

2965
        for (Class entity : objects) {
10 ✔
2966
                //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2967
                if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 ✔
2968
                    return entity;
2 ✔
2969
                }
2970
        }
1 ✔
2971

2972
        Class fmx = createFamixEntity(Class.class, "Object");
6 ✔
2973
        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
2974
                return fmx;
2 ✔
2975
        }
2976

2977
        /***
2978
         * We treat array types as parametrized types Array<T>.
2979
         * This keeps the meta-model simple: a single way to model different concepts.
2980
         * @return
2981
         */
2982
        public ParametricClass ensureParametricArrayClass() {
2983
                
2984
                Collection<ParametricClass> arrayClasses = getEntityByName(ParametricClass.class, "Array");
5 ✔
2985
                
2986
                for (ParametricClass entity : arrayClasses) {
10 ✔
2987
            //We need to cast because the type container is a FamixTWithType but all implementors of this should be named in Java...
2988
            if ("java.lang".equals(((TNamedEntity) entity.getTypeContainer()).getName())) {
7 !
2989
                return entity;
2 ✔
2990
            }
2991
                }
×
2992
                
2993
                //Create the parametric class
2994
                ParametricClass arrayClass = createFamixEntity(ParametricClass.class, "Array"); 
6 ✔
2995

2996
                //And now add the type parameter
2997
                TypeParameter fmxParam = this.ensureFamixTypeParameter(null, "T", arrayClass);
6 ✔
2998
                fmxParam.setGenericEntity(arrayClass);
3 ✔
2999
                fmxParam.setIsStub(true);
4 ✔
3000
                
3001
                //And the class is in java.lang
3002
                arrayClass.setTypeContainer(ensureFamixPackageJavaLang(null));
5 ✔
3003
                
3004
                return arrayClass;
2 ✔
3005
        }
3006

3007
        /**
3008
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
3009
         */
3010
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
3011
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
3012
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9 ✔
3013

3014
                if (fmx != null) {
2 !
3015
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7 ✔
3016
                }
3017

3018
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5 !
3019
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, null, null);
×
3020
                }
3021

3022
                return fmx;
2 ✔
3023
        }
3024

3025
        public Class getFamixMetaClass(ITypeBinding bnd) {
3026
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7 !
3027
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8 ✔
3028
        }
3029

3030
        /**
3031
         * Creates or recovers the Famix Class for all arrays (<pre>{@code <some-type> []}</pre>)
3032
         * In java arrays or objects of special classes (i.e. "I[" for an array of int).
3033
         * JDT does not create a binding for these classes, so we create a stub one here.
3034
         *
3035
         * @return a Famix class
3036
         */
3037
        public Class ensureFamixClassArray() {
3038
                Class fmx = ensureFamixUniqEntity(Class.class, null, ARRAYS_NAME);
×
3039
                if (fmx != null) {
×
3040
                        ensureFamixInheritance(ensureFamixClassObject(), fmx, /*prev*/null, null);
×
3041
                        fmx.setTypeContainer(ensureFamixPackageDefault());
×
3042

3043
                        // may be not needed anymore now that we use modifiers
3044
                        /*fmx.setIsAbstract(Boolean.FALSE);
3045
                        fmx.setIsFinal(Boolean.FALSE);
3046
                        fmx.setIsInterface(Boolean.FALSE); 
3047
                        fmx.setIsPrivate(Boolean.FALSE);
3048
                        fmx.setIsProtected(Boolean.FALSE);*/
3049
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
3050
                }
3051

3052
                return fmx;
×
3053
        }
3054

3055
        public String removeLastPartOfPackageName(String qualifiedName) {
3056
                String ret;
3057
                int last = qualifiedName.lastIndexOf('.');
4 ✔
3058
                if (last > 0) {
2 ✔
3059
                        // recursively creating the parent
3060
                        ret = qualifiedName.substring(0, last);
6 ✔
3061
                }
3062
                else {
3063
                        ret = "";
2 ✔
3064
                }
3065

3066
                return ret;
2 ✔
3067
        }
3068

3069
        /** Generates the list of parameters for a method signature
3070
         * @return a string
3071
         */
3072
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
3073
                boolean first = true;
2 ✔
3074
                String sig = "";
2 ✔
3075

3076
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17 ✔
3077
                        if (first) {
2 ✔
3078
                                sig = parBnd.getName();
3 ✔
3079
                                first = false;
3 ✔
3080
                        }
3081
                        else {
3082
                                sig += "," + parBnd.getName();
5 ✔
3083
                        }
3084
                }
3085
                return sig;
2 ✔
3086
        }
3087

3088
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
3089
                boolean first = true;
2 ✔
3090
                String sig = "";
2 ✔
3091

3092
                for (String t : paramTypes) {
10 ✔
3093
                        if (first) {
2 ✔
3094
                                sig = t;
2 ✔
3095
                                first = false;
3 ✔
3096
                        }
3097
                        else {
3098
                                sig += "," + t;
4 ✔
3099
                        }
3100
                }
1 ✔
3101
                return sig;
2 ✔
3102
        }
3103

3104
        public String findTypeName(org.eclipse.jdt.core.dom.Type t) {
3105
                if (t == null) {
×
3106
                        return null;
×
3107
                }
3108

3109
                if (t.isPrimitiveType()) {
×
3110
                        return t.toString();
×
3111
                } else if (t.isSimpleType()) {
×
3112
                        String fullName = ((SimpleType) t).getName().getFullyQualifiedName();
×
3113
                        int i = fullName.lastIndexOf('.');
×
3114
                        if (i > 0) {
×
3115
                                return fullName.substring(i+1);
×
3116
                        }
3117
                        else {
3118
                                return fullName;
×
3119
                        }
3120
                } else if (t.isQualifiedType()) {
×
3121
                        return ((QualifiedType) t).getName().getIdentifier();
×
3122
                } else if (t.isArrayType()) {
×
3123
                        return findTypeName(((ArrayType) t).getElementType());
×
3124
                } else if (t.isParameterizedType()) {
×
3125
                        return findTypeName(((org.eclipse.jdt.core.dom.ParameterizedType) t).getType());
×
3126
                } else { // it is a WildCardType
3127
                        if (((org.eclipse.jdt.core.dom.WildcardType) t).isUpperBound()) {
×
3128
                                return findTypeName(((org.eclipse.jdt.core.dom.WildcardType) t).getBound());
×
3129
                        } else {
3130
                                return EntityDictionary.OBJECT_NAME;
×
3131
                        }
3132
                }
3133
        }
3134

3135
        /**
3136
         * Ensures the proper creation of a FamixType for JDT typ in the given context.
3137
         * Useful for parameterizedTypes, or classInstance.
3138
         *
3139
         * @param isClass we are sure that the type is actually a class
3140
         * @return a famix type or null
3141
         */
3142
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass) {
3143
                return this.referredType(typ, ctxt, isClass, /*isExcep*/false);
7 ✔
3144
        }
3145
        
3146
        /**
3147
         * Ensures the proper creation of a FamixType for JDT type in the given context.
3148
         * Useful for parameterizedTypes, or classInstance.
3149
         *
3150
         * @param isClass we are sure that the type is actually a class
3151
         * @return a famix type or null
3152
         */
3153
        public <T extends TWithTypes & TNamedEntity> TType referredType(org.eclipse.jdt.core.dom.Type typ, T ctxt, boolean isClass, boolean isException) {
3154
                if (typ == null) {
2 !
3155
                        return null;
×
3156
                } else if (typ.resolveBinding() != null) {
3 !
3157
                        return this.referredType(typ.resolveBinding(), ctxt);
7 ✔
3158
                }
3159
                // from here, we assume the owner is the context
3160
                else if (isClass && !isException) {
×
3161
                        return this.ensureFamixClass(null, findTypeName(typ), /*owner*/ctxt, /*isGeneric*/false,
×
3162
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3163
                } else if (isException) {
×
3164
                        // return ensure FamixException
3165
                        return this.ensureFamixException(null, findTypeName(typ), (ContainerEntity) /*owner*/ctxt, /*isGeneric*/false,
×
3166
                                        EntityDictionary.UNKNOWN_MODIFIERS);
3167
                } else {
3168
                        while (typ.isArrayType()) {
×
3169
                                typ = ((ArrayType) typ).getElementType();
×
3170
                        }
3171

3172
                        if (typ.isPrimitiveType()) {
×
3173
                                return this.ensureFamixPrimitiveType(null, findTypeName(typ));
×
3174
                        } else {
3175
                                return this.ensureFamixType(null, findTypeName(typ), /*owner*/ctxt, /*container*/ctxt,
×
3176
                                                EntityDictionary.UNKNOWN_MODIFIERS);
3177
                        }
3178
                }
3179
        }
3180
        
3181
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt) {
3182
                return this.referredType(bnd, ctxt, 0);
6 ✔
3183
        }
3184
        
3185
        public TType referredType(ITypeBinding bnd, TNamedEntity ctxt, int extraDimensions) {
3186
                TType fmxTyp = null;
2 ✔
3187

3188
                if (bnd == null) {
2 ✔
3189
                        return null;
2 ✔
3190
                }
3191

3192
                String name;
3193
                //Three cases here:
3194
                // - the type binding knows it's an array
3195
                // - the binding is not declared as array, but it has dimensions > 0
3196
                // - the dimension is not in the type but in the variable declaration (thus extra)
3197
                if (bnd.isArray() || bnd.getDimensions() + extraDimensions > 0) {
8 ✔
3198
                        // We treat array types as parametrized types Array<T>.
3199
                        // This keeps the meta-model simple: a single way to model different concepts.
3200
                        return this.ensureParametricArrayClass();
3 ✔
3201
                }
3202
                name = bnd.getName();
3 ✔
3203

3204
                if ( bnd.isParameterizedType() ) {
3 ✔
3205
                        
3206
                        // remove type parameters from the name even for parameterized interfaces
3207
                        int i = name.indexOf('<');
4 ✔
3208
                        if (i > 0) {
2 ✔
3209
                                name = name.substring(0, i);
5 ✔
3210
                        }
3211

3212
                        ITypeBinding parameterizableBnd = bnd.getErasure();
3 ✔
3213
                        int modifiers = (parameterizableBnd != null) ? parameterizableBnd.getModifiers() : EntityDictionary.UNKNOWN_MODIFIERS;
6 !
3214
                        
3215
                        if(parameterizableBnd != null && parameterizableBnd.isInterface()) {
5 !
3216
                                fmxTyp = (ParametricInterface) this.ensureFamixInterface(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
10 ✔
3217
                        } else {
3218
                                fmxTyp = (ParametricClass) this.ensureFamixClass(parameterizableBnd, name, /*owner*/null, /*isGeneric*/true, modifiers);
9 ✔
3219
                        }
3220
                } else if ( (name != null) && name.equals("var") ) {
7 !
3221
                        fmxTyp = this.ensureFamixUniqEntity(org.moosetechnology.model.famix.famixjavaentities.Type.class, /*binding*/null, EntityDictionary.IMPLICIT_VAR_TYPE_NAME);        
×
3222
                } else {
3223
                        fmxTyp = this.ensureFamixType(bnd, name, /*owner*/null, (TWithTypes) ctxt, bnd.getModifiers());
10 ✔
3224
                }
3225

3226
                return fmxTyp;
2 ✔
3227
        }
3228

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