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

moosetechnology / VerveineJ / 16630354751

30 Jul 2025 06:10PM UTC coverage: 50.681% (+0.7%) from 49.972%
16630354751

Pull #147

github

web-flow
Merge 307520ee4 into 5207a6c7c
Pull Request #147: Issue/146

1892 of 3962 branches covered (47.75%)

Branch coverage included in aggregate %.

519 of 1127 new or added lines in 53 files covered. (46.05%)

53 existing lines in 10 files now uncovered.

4282 of 8220 relevant lines covered (52.09%)

2.08 hits per line

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

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

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

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

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

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

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

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

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

101
        /**
102
         * An MSE marker for methods
103
         */
104
        public static final String CONSTRUCTOR_KIND_MARKER = "constructor";
105

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

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

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

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

133
        /**
134
         * Used to keep the two possible ImplicitVariable for a given Class binding
135
         * @author anquetil
136
         */
137
        @Deprecated
138
        protected class ImplicitVars {
×
139
                public ImplicitVariable self_iv;
140
                public ImplicitVariable super_iv;
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
        /** Constructor taking a FAMIX repository
152
         * @param famixRepo
153
         */
154
        public EntityDictionary(Repository famixRepo) {
2✔
155
                        this.famixRepo = famixRepo;
3✔
156
                        
157
                        this.keyToEntity = new Hashtable<IBinding,TNamedEntity>();
5✔
158
                        this.entityToKey = new Hashtable<TNamedEntity,IBinding>();
5✔
159
                        this.nameToEntity = new Hashtable<String,Collection<TNamedEntity>>();
5✔
160
                        this.typeToImpVar = new Hashtable<Type,ImplicitVars>();
5✔
161
                        
162
                        if (! this.famixRepo.isEmpty()) {
4✔
163
                                recoverExistingRepository();
2✔
164
                        }
165
                }
1✔
166

167
          public void mapKey(IBinding bnd, NamedEntity fmx) {
168
                mapEntityToKey(bnd, fmx);
×
169
        }
×
170

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

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

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

203
        public void removeEntity( NamedEntity ent) {
204
                IBinding key;
205
                key = entityToKey.get(ent);
6✔
206
                entityToKey.remove(ent);
5✔
207
                keyToEntity.remove(key);
5✔
208

209
                Collection<TNamedEntity> l_ent = nameToEntity.get(ent.getName());
7✔
210
                l_ent.remove(ent);
4✔
211

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

243
                return ret;
2✔
244
        }
245

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

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

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

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

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

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

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

351

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

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

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

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

424
        ///// ensure Famix Relationships /////
425

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

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

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

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

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

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

481
                return association;
2✔
482
        }
483

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

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

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

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

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

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

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

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

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

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

591
                return ref;
2✔
592
        }
593

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

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

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

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

672
        /**
673
         * Returns a Famix CaughtException between a method and an Exception that is caught
674
         * @param meth -- the method catching the exception
675
         * @param excep -- the exception caught
676
         * @return the CaughtException
677
         */
678
        public TThrowable createFamixCaughtException(Method meth, TThrowable excep) {
679
                if ( (meth == null) || (excep == null) ) {
4!
680
                        return null;
×
681
                }
682
                // CaughtException decl = new CaughtException();
683
                // decl.setExceptionClass(excep);
684
                // decl.setDefiningEntity(meth);
685
                // famixRepoAdd(decl);
686
                meth.getCaughtExceptions().add(excep);
5✔
687
                return excep;
2✔
688
        }
689

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

710

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

734

735
        ///// Special Case: ImplicitVariables /////
736

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

770
                return ret;
×
771
        }
772

773
        ///// Special Case: "Uniq" Entities /////
774

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

812
                return fmx;
2✔
813
        }
814

815
        /**
816
         * Creates or recovers the Famix Class that will own all stub methods (for which the real owner is unknown)
817
         *
818
         * @return a Famix class
819
         */
820
        public Class ensureFamixClassStubOwner() {
821
                Class fmx =  ensureFamixUniqEntity(Class.class, null, STUB_METHOD_CONTAINER_NAME);
7✔
822
                if (fmx != null) {
2!
823
                        fmx.setTypeContainer( ensureFamixPackageDefault());
4✔
824
                }
825
                ensureFamixInheritance(ensureFamixClassObject(null), fmx, /*prev*/null, null);
9✔
826

827
                return fmx;
2✔
828
        }
829

830
        public Type searchTypeInContext(String name, TWithTypes ctxt) {
831
                if (ctxt == null) {
×
832
                        return null;
×
833
                }
834
                
835
                for (TType candidate : ctxt.getTypes()) {
×
836
                        if (((TNamedEntity)candidate).getName().equals(name) ) {
×
837
                                return (Type) candidate;
×
838
                        }
839
                }
×
840
                
841
                return searchTypeInContext(name, Util.getOwner((TNamedEntity)ctxt));
×
842
        }
843

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

859
                if ((name == null) && (bnd != null)) {
4!
860
                        name = bnd.getName();
3✔
861
                }
862

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

881
                return fmx;
2✔
882
        }
883

884
        /**
885
         * Creates or recovers a default Famix Package.
886
         * Because this package does not really exist, it has no binding.
887
         *
888
         * @return a Famix Namespace
889
         */
890
        public Package ensureFamixPackageDefault() {
891
                Package fmx = ensureFamixUniqEntity(Package.class, null, DEFAULT_PCKG_NAME);
7✔
892

893
                return fmx;
2✔
894
        }
895

896
        /**
897
         * Creates or recovers a Famix Package for the package of Java class "Object" (i.e. "java.lang").
898
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
899
         *
900
         * @param bnd -- a potential binding for the "java.lang" package
901
         * @return a Famix Namespace for "java.lang"
902
         */
903
        public Package ensureFamixPackageJavaLang(IPackageBinding bnd) {
904
                Package fmx = this.ensureFamixPackage(bnd, OBJECT_PACKAGE_NAME);
5✔
905

906
                return fmx;
2✔
907
        }
908

909
        /**
910
         * Returns the Package with {@link #DEFAULT_PCKG_NAME} or <code>null</code> if not found
911
         */
912
        public Package getFamixPackageDefault() {
913
                Collection<Package> l = getEntityByName(Package.class, DEFAULT_PCKG_NAME);
5✔
914
                if (l.size() > 0) {
3!
915
                        return l.iterator().next();
5✔
916
                } else {
917
                        return null;
×
918
                }
919
        }
920

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

933
                if (bnd == null) {
2✔
934
                        if (name == null) {
2!
935
                                return null;
2✔
936
                        }
937
                        fmx = searchTypeInContext(name, ctxt); // WildCard Types don't have binding
×
938
                        if (fmx != null) {
×
939
                                return fmx;
×
940
                        }
941

942
                        if ( (owner != null) && (owner instanceof TParametricEntity) ) {
×
NEW
943
                                return this.ensureFamixTypeParameter(null, name, owner);
×
944
                        }
945
                        else {
946
                                fmx = ensureFamixEntity(Type.class, bnd, name);
×
947
                                fmx.setTypeContainer(owner);
×
948
                                return fmx;
×
949
                        }
950
                }
951

952
                // bnd != null
953

954
                fmx = (TType) getEntityByKey(bnd);
5✔
955
                if (fmx != null) {
2✔
956
                        return fmx;
2✔
957
                }
958

959
                if (bnd.isArray()) {
3!
960
                        bnd = bnd.getElementType();
×
961
                }
962

963
                if (bnd.isPrimitive()) {
3✔
964
                        return this.ensureFamixPrimitiveType(bnd, name);
5✔
965
                }
966

967
                if (bnd.isEnum()) {
3!
968
                        return this.ensureFamixEnum(bnd, name, (ContainerEntity) owner);
×
969
                }
970

971
                if ((bnd.isRawType() || bnd.isGenericType()) && !bnd.isInterface() ) {
9✔
972
                        return this.ensureFamixClass(bnd.getErasure(), name, (TNamedEntity) owner, /*isGeneric*/true, modifiers);
10✔
973
                }
974
                
975
                if (bnd.isAnnotation()) {
3!
976
                        return this.ensureFamixAnnotationType(bnd, name, (ContainerEntity) owner);
×
977
                }
978

979
                if (bnd.isInterface()) {
3✔
980
                        return this.ensureFamixInterface(bnd, name, owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
19✔
981
                }
982

983
                if (isThrowable(bnd)) {
4✔
984
                        return this.ensureFamixException(bnd, name, owner, /*isGeneric*/false, modifiers);
8✔
985
                }
986
                if (bnd.isClass()) {
3✔
987
                        return this.ensureFamixClass(bnd, name, (TNamedEntity) owner, /*isGeneric*/bnd.isGenericType() || bnd.isParameterizedType() || bnd.isRawType(), modifiers);
20!
988
                }
989
                if(bnd.isWildcardType()) {
3✔
990
                        return this.ensureFamixWildcardType(bnd, name, (TParametricEntity)owner, ctxt);
8✔
991
                }
992

993
                //otherwise (none of the above)
994

995
                if (name == null) {
2✔
996
                        name = bnd.getName();
3✔
997
                }
998

999
                if (owner == null) {
2!
1000
                        owner = (TWithTypes) this.ensureOwner(bnd);
5✔
1001
                }
1002

1003
                if (bnd.isTypeVariable() ) {
3!
1004
                        fmx = ensureFamixTypeParameter(bnd, name, owner);
6✔
1005
                        return fmx;
2✔
1006
                }
1007

1008
                fmx = ensureFamixEntity(Type.class, bnd, name);
×
1009
                fmx.setTypeContainer(owner);
×
1010
                return fmx;
×
1011
        }
1012

1013
        public TType ensureFamixType(ITypeBinding bnd, TWithTypes context) {
1014
                int modifiers = extractModifierOfTypeFrom(bnd);
4✔
1015
                return ensureFamixType(bnd, /*name*/null, /*owner*/null, context, modifiers);
8✔
1016
        }
1017
        
1018
        public TType ensureFamixType(ITypeBinding bnd) {
1019
                return ensureFamixType(bnd, /*ctxt*/null);
5✔
1020
        }
1021

1022
        private int extractModifierOfTypeFrom(ITypeBinding bnd) {
1023
                int modifiers = (bnd != null) ? bnd.getModifiers() : UNKNOWN_MODIFIERS;
7✔
1024
                return modifiers;
2✔
1025
        }
1026

1027
        public boolean isThrowable(ITypeBinding bnd) {
1028
                if (bnd == null) {
2!
1029
                        return false;
×
1030
                }
1031
                if (bnd.getQualifiedName().equals("java.lang.Throwable")) {
5✔
1032
                        return true;
2✔
1033
                } else if (bnd.getQualifiedName().equals("java.lang.Object")) {
5✔
1034
                        return false;
2✔
1035
                }
1036
                else {
1037
                        return isThrowable(bnd.getSuperclass());
5✔
1038
                }
1039
        }
1040

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

1052
                // --------------- some special cases
1053
                if (bnd != null) {
2✔
1054
                        if (bnd.isArray()) {
3!
1055
                                bnd = bnd.getElementType();
×
1056
                        }
1057

1058
                        // for inner classes defined in generics !!! For others should not change anything
1059
                        bnd = bnd.getErasure();
3✔
1060
                }
1061

1062
                // ---------------- to avoid useless computations if we can
1063
                fmx = (Class) getEntityByKey(bnd);
5✔
1064
                if (fmx != null) {
2✔
1065
                        return fmx;
2✔
1066
                }
1067

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

1091
                if (name.equals(OBJECT_NAME)) { // TODO && owner == java.lang
4✔
1092
                        return ensureFamixClassObject(bnd);
4✔
1093
                }
1094

1095
                // --------------- owner
1096
                if (owner == null) {
2✔
1097
                        if (bnd != null) {
2✔
1098
                                owner = ensureOwner(bnd);
4✔
1099
                        }
1100
                        /*                                owner = ensureFamixPackageDefault();
1101
                        } else {*/
1102
                }
1103

1104
                // --------------- recover from name ?
1105
                if (owner != null) {
2✔
1106
                        for (Class candidate : this.getEntityByName(Class.class, name)) {
13✔
1107
                                if (matchAndMapClass(bnd, name, (ContainerEntity) owner, candidate)) {
8✔
1108
                                        fmx = candidate;
2✔
1109
                                        break;
1✔
1110
                                }
1111
                        }
1✔
1112
                }
1113

1114
                // ---------------- create
1115
                if (fmx == null) {
2✔
1116
                        if (isGeneric) {
2✔
1117
                                fmx = ensureFamixParametricClass(bnd, name, (TWithTypes) owner);
8✔
1118
                        }
1119
                        else {
1120
                                fmx = ensureFamixEntity(Class.class, bnd, name);
7✔
1121
                                fmx.setTypeContainer((TWithTypes)owner);
4✔
1122
                        }
1123
                }
1124

1125
                if (fmx!=null) {
2!
1126
                        // we just created it or it was not bound, so we make sure it has the right information in it
1127
                        if (bnd != null) {
2✔
1128
                                setClassModifiers(fmx, bnd.getDeclaredModifiers());
5✔
1129
                        }
1130
                        TAssociation lastAssoc = null;
2✔
1131

1132
                        if (bnd != null) {
2✔
1133
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1134
                                if (supbnd != null) {
2✔
1135
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1136
                                }
1137
                                else {
1138
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixClassObject(null), fmx, lastAssoc, null);
9✔
1139
                                }
1140
                                ensureImplementedInterfaces(bnd, fmx, (TWithTypes) owner, lastAssoc);
7✔
1141
                        }
1142
                }
1143

1144
                return fmx;
2✔
1145
        }
1146

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

1158
                // --------------- some special cases
1159
                if (bnd != null) {
2✔
1160
                        if (bnd.isArray()) {
3!
1161
                                bnd = bnd.getElementType();
×
1162
                        }
1163

1164
                        // for inner classes defined in generics !!! For others should not change anything
1165
                        bnd = bnd.getErasure();
3✔
1166
                }
1167

1168
                // ---------------- to avoid useless computations if we can
1169
                fmx = (Exception) getEntityByKey(bnd);
5✔
1170
                if (fmx != null) {
2✔
1171
                        return fmx;
2✔
1172
                }
1173

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

1197
                // --------------- owner
1198
                if (owner == null) {
2✔
1199
                        if (bnd == null) {
2✔
1200
                                owner = ensureFamixPackageDefault();
4✔
1201
                        } else {
1202
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1203
                        }
1204
                }
1205

1206
                // --------------- recover from name ?
1207
                for (Exception candidate : this.getEntityByName(Exception.class, name)) {
13✔
1208
                        if (matchAndMapClass(bnd, name, (T) owner, candidate)) {
8✔
1209
                                fmx = candidate;
2✔
1210
                                break;
1✔
1211
                        }
1212
                }
1✔
1213

1214
                // ---------------- create
1215
                if (fmx == null) {
2✔
1216
                        fmx = ensureFamixEntity(Exception.class, bnd, name);
7✔
1217
                        fmx.setTypeContainer(owner);
3✔
1218
                }
1219

1220
                if (fmx!=null) {
2!
1221
                        // we just created it or it was not bound, so we make sure it has the right information in it
1222
                        TAssociation lastAssoc = null;
2✔
1223
                        if (bnd != null) {
2✔
1224
                                ITypeBinding supbnd = bnd.getSuperclass();
3✔
1225
                                if (supbnd != null) {
2!
1226
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixType(supbnd), fmx, lastAssoc, supbnd);
11✔
1227
                                }
1228
                                else {
NEW
1229
                                        lastAssoc = ensureFamixInheritance((TWithInheritances) ensureFamixClassObject(null), fmx, lastAssoc, null);
×
1230
                                }
1231
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssoc);
6✔
1232
                        }
1233
                }
1234

1235
                return fmx;
2✔
1236
        }
1237

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

1247
                // --------------- some special cases
1248
                if (bnd != null) {
2!
1249
                        if (bnd.isArray()) {
3!
1250
                                bnd = bnd.getElementType();
×
1251
                        }
1252

1253
                        // for inner classes defined in generics !!! For others should not change anything
1254
                        bnd = bnd.getErasure();
3✔
1255
                }
1256

1257
                // ---------------- to avoid useless computations if we can
1258
                fmx = (Interface) getEntityByKey(bnd);
5✔
1259
                if (fmx != null) {
2✔
1260
                        return fmx;
2✔
1261
                }
1262

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

1286
                // --------------- owner
1287
                if (owner == null) {
2✔
1288
                        if (bnd == null) {
2!
1289
                                owner = ensureFamixPackageDefault();
×
1290
                        } else {
1291
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1292
                        }
1293
                }
1294

1295
                // --------------- recover from name ?
1296
                for (Interface candidate : this.getEntityByName(Interface.class, name)) {
13✔
1297
                        if (matchAndMapInterface(bnd, name, (T) owner, candidate)) {
8✔
1298
                                fmx = candidate;
2✔
1299
                                break;
1✔
1300
                        }
1301
                }
1✔
1302

1303
                // ---------------- create
1304
                if (fmx == null) {
2✔
1305
                        if (isGeneric) {
2✔
1306
                                fmx = ensureFamixParametricInterface(bnd, name, owner);
7✔
1307
                        }
1308
                        else {
1309
                                fmx = ensureFamixEntity(Interface.class, bnd, name);
7✔
1310
                                fmx.setTypeContainer(owner);
3✔
1311
                        }
1312
                }
1313

1314
                if (fmx!=null) {
2!
1315
                        // we just created it or it was not bound, so we make sure it has the right information in it
1316
                        if (bnd != null) {
2!
1317
                                setInterfaceModifiers(fmx, bnd.getModifiers());
5✔
1318
                        }
1319
                        TAssociation lastAssociation = null;
2✔
1320
                        if (bnd != null) {
2!
1321
                                ensureImplementedInterfaces(bnd, fmx, owner, lastAssociation);
6✔
1322
                        }
1323
                }
1324
                return fmx;
2✔
1325
        }
1326

1327
        public TType asClass(TType excepFmx) {
1328
                Class tmp = null;
×
1329
                IBinding key = null;
×
1330
                try {
1331
                        TWithTypes owner = (TWithTypes) Util.getOwner(excepFmx);
×
1332
                        owner.getTypes().remove(excepFmx);
×
1333
                        removeEntity((NamedEntity) excepFmx);
×
1334

1335
                        key = entityToKey.get((NamedEntity) excepFmx);
×
1336
                        tmp = ensureFamixEntity(Class.class, key, excepFmx.getName());
×
1337
                        tmp.setTypeContainer((ContainerEntity)owner);
×
1338

1339
                        tmp.addMethods(((TWithMethods) excepFmx).getMethods());
×
1340
                        if (excepFmx instanceof TWithAttributes) {
×
1341
                                tmp.addAttributes(((TWithAttributes) excepFmx).getAttributes());
×
1342
                        }
1343

1344
                        if (key != null) {
×
1345
                                setClassModifiers(tmp, key.getModifiers());
×
1346
                        }
1347

1348
                        if (excepFmx instanceof TWithInheritances) {
×
1349
                                tmp.addSuperInheritances(((TWithInheritances) excepFmx).getSuperInheritances());
×
1350
                                tmp.addSubInheritances(((TWithInheritances) excepFmx).getSubInheritances());
×
1351
                        }
1352
                        tmp.setSourceAnchor(excepFmx.getSourceAnchor());
×
1353
                        tmp.addAnnotationInstances(((NamedEntity) excepFmx).getAnnotationInstances());
×
1354
                        // tmp.addComments(excepFmx.getComments());
1355
                        tmp.addIncomingReferences(excepFmx.getIncomingReferences());
×
1356
                        tmp.setIsStub(excepFmx.getIsStub());
×
1357
                        tmp.addTypes(((ContainerEntity) excepFmx).getTypes());
×
1358
                }
1359
                catch( ConcurrentModificationException e) {
×
1360
                        e.printStackTrace();
×
1361
                }
×
1362

1363
                return tmp;
×
1364
        }
1365

1366
        public TThrowable asException(TType excepFmx) {
1367
                if (excepFmx instanceof Exception) {
3✔
1368
                        return (Exception) excepFmx;
3✔
1369
                }
1370
                if(excepFmx instanceof TypeParameter) {
3✔
1371
                        return (TypeParameter) excepFmx;
3✔
1372
                }
1373
                Exception tmp = null;
2✔
1374
                IBinding key = null;
2✔
1375
                try {
1376
                        TWithTypes owner = (TWithTypes) Util.getOwner(excepFmx);
4✔
1377
                        owner.getTypes().remove(excepFmx);
5✔
1378
                        removeEntity((NamedEntity) excepFmx);
4✔
1379

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

1383
                        tmp.addMethods(((TWithMethods) excepFmx).getMethods());
5✔
1384
                        if (excepFmx instanceof TWithAttributes) {
3!
1385
                                tmp.addAttributes(((TWithAttributes) excepFmx).getAttributes());
5✔
1386
                        }
1387

1388
                        if (excepFmx instanceof TWithInheritances) {
3!
1389
                                tmp.addSuperInheritances(((TWithInheritances) excepFmx).getSuperInheritances());
5✔
1390
                                tmp.addSubInheritances(((TWithInheritances) excepFmx).getSubInheritances());
5✔
1391
                        }
1392
                        tmp.setSourceAnchor(excepFmx.getSourceAnchor());
4✔
1393
                        tmp.addAnnotationInstances(((NamedEntity) excepFmx).getAnnotationInstances());
5✔
1394
                        // tmp.addComments(excepFmx.getComments());
1395
                        List<TReference> newList = excepFmx.getIncomingReferences().stream().collect(Collectors.toList());
7✔
1396
                        tmp.addIncomingReferences(newList);
3✔
1397
                        tmp.setIsStub(excepFmx.getIsStub());
4✔
1398
                        tmp.addTypes(((ContainerEntity) excepFmx).getTypes());
5✔
1399
                }
1400
                catch( ConcurrentModificationException e) {
×
1401
                        e.printStackTrace();
×
1402
                }
1✔
1403

1404
                return (TThrowable)tmp;
2✔
1405
        }
1406

1407
        /**
1408
         * helper method, we know the type exists, ensureFamixClass will recover it
1409
         */
1410
        public Class getFamixClass(ITypeBinding bnd, String name, TNamedEntity owner) {
1411
                return ensureFamixClass(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1412
        }
1413

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

1421
        /**
1422
         * helper method, we know the type exists, ensureFamixInterface will recover it
1423
         */
1424
        public Exception getFamixException(ITypeBinding bnd, String name, TWithTypes owner) {
1425
                return ensureFamixException(bnd, name, owner, /*isGeneric*/false, UNKNOWN_MODIFIERS);
8✔
1426
        }
1427

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

1463

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

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

1484
                // --------------- to avoid useless computations if we can
1485
                fmx = (org.moosetechnology.model.famix.famixjavaentities.Enum) getEntityByKey(bnd);
5✔
1486
                if (fmx != null) {
2✔
1487
                        return fmx;
2✔
1488
                }
1489

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

1500
                // --------------- owner
1501
                if (owner == null) {
2✔
1502
                        if (bnd == null) {
2!
1503
                                owner = ensureFamixPackageDefault();  // not really sure what to do here
×
1504
                        } else {
1505
                                owner = (TWithTypes) ensureOwner(bnd);
5✔
1506
                        }
1507
                }
1508

1509
                // --------------- recover from name ?
1510
                for (org.moosetechnology.model.famix.famixjavaentities.Enum candidate : getEntityByName(org.moosetechnology.model.famix.famixjavaentities.Enum.class, name)) {
9!
1511
                        if (matchAndMapType(bnd, name, (T) owner, candidate)) {
×
1512
                                fmx = candidate;
×
1513
                                break;
×
1514
                        }
1515
                }
×
1516

1517
                if (fmx == null) {
2!
1518
                        fmx = ensureFamixEntity(Enum.class, bnd, name);
7✔
1519
                        fmx.setTypeContainer(owner);
3✔
1520
                }
1521

1522
                if ((fmx != null) && (bnd != null) ) {
4!
1523
                        setVisibility(fmx, bnd.getModifiers());
5✔
1524
                }
1525

1526
                return fmx;
2✔
1527
        }
1528

1529
        /**
1530
         * helper method, we know the type exists, ensureFamixEnum will recover it
1531
         */
1532
        public org.moosetechnology.model.famix.famixjavaentities.Enum getFamixEnum(ITypeBinding bnd, String name, TWithTypes owner) {
1533
                return ensureFamixEnum(bnd, name, owner);
6✔
1534
        }
1535

1536
        public EnumValue ensureFamixEnumValue(IVariableBinding bnd,        String name, Enum owner) {
1537
                EnumValue fmx = null;
2✔
1538

1539
                // --------------- to avoid useless computations if we can
1540
                fmx = (EnumValue)getEntityByKey(bnd);
5✔
1541
                if (fmx != null) {
2✔
1542
                        return fmx;
2✔
1543
                }
1544

1545
                // --------------- name
1546
                if (name == null) {
2!
1547
                        if (bnd == null) {
×
1548
                                return null;
×
1549
                        }
1550
                        else {
1551
                                name = bnd.getName();
×
1552
                        }
1553
                }
1554

1555
                // --------------- owner
1556
                if (owner == null) {
2✔
1557
                        if (bnd == null) {
2!
1558
                                return null;  // what would be the interest of creating an EnumValue without a declaring Enum type?
×
1559
                        }
1560
                        else {
1561
                                owner = ensureFamixEnum(bnd.getDeclaringClass(), null, null);
7✔
1562
                        }
1563
                }
1564

1565
                // --------------- recover from name ?
1566
                for (EnumValue candidate : getEntityByName(EnumValue.class, name) ) {
9!
1567
                        if ( matchAndMapVariable(bnd, name, owner, candidate) ) {
×
1568
                                fmx = candidate;
×
1569
                                break;
×
1570
                        }
1571
                }
×
1572
                if (fmx == null) {
2!
1573
                        fmx = ensureFamixEntity(EnumValue.class, bnd, name);
7✔
1574
                        fmx.setParentEnum(owner);
3✔
1575
                }
1576

1577
                if (fmx!=null) {
2!
1578
                        fmx.setParentEnum(owner);
3✔
1579
                }
1580

1581
                return fmx;
2✔
1582
        }
1583

1584
        /**
1585
         * helper method, we know the type enumValue, ensureFamixEnumValue will recover it
1586
         */
1587
        public EnumValue getFamixEnumValue(IVariableBinding bnd, String name, Enum owner) {
1588
                return ensureFamixEnumValue(bnd, name, owner);
×
1589
        }
1590

1591
        /**
1592
         * e.g. see {@link EntityDictionary#ensureFamixClass}
1593
         */
1594
        public AnnotationType ensureFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1595
                AnnotationType fmx = null;
2✔
1596

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

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

1613
                // --------------- owner
1614
                if (owner == null) {
2✔
1615
                        if (bnd == null) {
2!
1616
                                owner = ensureFamixPackageDefault();
×
1617
                        }
1618
                        else {
1619
                                IPackageBinding parentPckg = bnd.getPackage();
3✔
1620
                                if (parentPckg != null) {
2!
1621
                                        owner = this.ensureFamixPackage(parentPckg, null);
6✔
1622
                                } else {
1623
                                        owner = this.ensureFamixPackageDefault();
×
1624
                                }
1625
                        }
1626
                }
1627

1628
                // --------------- recover from name ?
1629
                for (AnnotationType candidate : getEntityByName(AnnotationType.class, name) ) {
13✔
1630
                        if ( matchAndMapType(bnd, name, owner, candidate) ) {
7✔
1631
                                fmx = candidate;
2✔
1632
                                break;
1✔
1633
                        }
1634
                }
1✔
1635

1636
                // --------------- create
1637
                if (fmx == null) {
2✔
1638
                        fmx = ensureFamixEntity(AnnotationType.class, bnd, name);
7✔
1639
                        fmx.setAnnotationTypesContainer(owner);
3✔
1640
                }
1641

1642
                if ( (fmx!=null) && (bnd != null) ) {
4!
1643
                        // Not supported in Famix
1644

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

1648
                return fmx;
2✔
1649
        }
1650

1651
        /**
1652
         * helper method, we know the type exists, ensureFamixAnnotationType will recover it
1653
         */
1654
        public AnnotationType getFamixAnnotationType(ITypeBinding bnd, String name, ContainerEntity owner) {
1655
                return ensureFamixAnnotationType(bnd, name, owner);
6✔
1656
        }
1657

1658
        public AnnotationTypeAttribute ensureFamixAnnotationTypeAttribute(IMethodBinding bnd, String name, AnnotationType owner) {
1659
                AnnotationTypeAttribute fmx = null;
2✔
1660

1661
                // --------------- to avoid useless computations if we can
1662
                fmx = (AnnotationTypeAttribute)getEntityByKey(bnd);
5✔
1663
                if (fmx != null) {
2✔
1664
                        return fmx;
2✔
1665
                }
1666

1667
                // --------------- name
1668
                if (name == null) {
2!
1669
                        if (bnd == null) {
×
1670
                                return null;
×
1671
                        }
1672
                        else {
1673
                                name = bnd.getName();
×
1674
                        }
1675
                }
1676

1677
                // --------------- owner
1678
                if (owner == null) {
2!
1679
                        if (bnd == null) {
×
1680
                                return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1681
                        }
1682
                        else {
1683
                                ITypeBinding parentType = bnd.getDeclaringClass();
×
1684
                                if (parentType != null) {
×
1685
                                        owner = this.ensureFamixAnnotationType(parentType, null, null);
×
1686
                                }
1687
                                else  {
1688
                                        return null;  // what would be the use of an AnnotationTypeAttribute without AnnotationType ?
×
1689
                                }
1690
                        }
1691
                }
1692

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

1708
                if (fmx == null) {
2!
1709
                        fmx = ensureFamixEntity(AnnotationTypeAttribute.class, bnd, name);
7✔
1710
                        fmx.setParentType(owner);
3✔
1711
                }
1712

1713
                if ( (fmx!=null) && (bnd != null) ) {
4!
1714
                        // Not suopp
1715

1716
                        // setVisibility(fmx, bnd.getModifiers());
1717
                }
1718

1719
                return fmx;
2✔
1720
        }
1721

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

1752
        /**
1753
         * Returns a Famix TypeParameter (created by a Famix ParametricEntity) with the given <b>name</b>, creating it if it does not exist yet
1754
         * In the second case, sets some default properties: not Abstract, not Final, not Private, not Protected, not Public
1755
         * @param name -- the name of the Famix TypeParameter
1756
         * @return the Famix TypeParameter or null in case of a Famix error
1757
         */
1758
        public TypeParameter ensureFamixTypeParameter(ITypeBinding bnd,        String name, TWithTypes owner) {
1759
                TypeParameter fmx = null;
2✔
1760

1761
                // --------------- to avoid useless computations if we can
1762
                fmx = (TypeParameter)getEntityByKey(bnd);
5✔
1763
                if (fmx != null) {
2✔
1764
                        return fmx;
2✔
1765
                }
1766

1767
                // --------------- name
1768
                if (name == null) {
2✔
1769
                        if (bnd == null) {
2!
1770
                                return null;
×
1771
                        }
1772
                        else {
1773
                                name = bnd.getName();
3✔
1774
                        }
1775
                }
1776

1777
                // --------------- owner
1778
                if (owner == null) {
2!
UNCOV
1779
                        if (bnd == null) {
×
1780
                                owner = null;  // not really sure what to do here
×
1781
                        }
1782
                        else {
UNCOV
1783
                                if (bnd.getDeclaringClass() != null) {
×
NEW
1784
                                        owner = (TWithTypes) this.ensureFamixType(bnd.getDeclaringClass());
×
UNCOV
1785
                                }else if(bnd.getDeclaringMethod() != null) {
×
NEW
1786
                                        owner = (TWithTypes) this.ensureFamixMethod(bnd.getDeclaringMethod());
×
1787
                                }
1788
                                else {
1789
                                        owner = null;  // not really sure what to do here
×
1790
                                }
1791
                        }
1792
                }
1793

1794
                // --------------- recover from name ?
1795
                for (Type candidate : this.getEntityByName(Type.class, name)) {
13✔
1796
                        if ( matchAndMapType(bnd, name, (ContainerEntity) owner, candidate) ) {
8✔
1797
                                fmx = (TypeParameter) candidate;
3✔
1798
                                break;
1✔
1799
                        }
1800
                }
1✔
1801

1802
                // --------------- create
1803
                if (fmx == null) {
2✔
1804
                        fmx = ensureFamixEntity(TypeParameter.class, bnd, name);
7✔
1805
                        if(bnd != null && bnd.getSuperclass() != null) {
5!
1806
                                Type upperBound = (Type)ensureFamixType(bnd.getSuperclass());
6✔
1807
                                fmx.setUpperBound(upperBound);
3✔
1808
                        }
1809
                        if(bnd != null && bnd.getInterfaces().length > 0) {
6✔
1810
                                for(ITypeBinding intbnd: bnd.getInterfaces()) {
17✔
1811
                                        Type upperBound = (Type)ensureFamixType(intbnd);
5✔
1812
                                        fmx.setUpperBound(upperBound);
3✔
1813
                                }
1814
                        }
1815
                        fmx.setTypeContainer((ContainerEntity) owner);
4✔
1816
                }
1817

1818
                return fmx;
2✔
1819
        }
1820

1821

1822
        public IBinding getTypeParameterOwner(ITypeBinding typeParameterBinding, IBinding currentOwner) {
1823
                
1824

1825

NEW
1826
                return currentOwner;
×
1827
        }
1828

1829

1830

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

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

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

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

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

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

1887
                if ( (bnd != null) && (bnd.isArray()) ) {
5!
1888
                                bnd = bnd.getElementType();
×
1889
                }
1890

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

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

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

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

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

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

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

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

1954
                return false;
2✔
1955
        }
1956

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

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

1979
                if (checkNameMatch(bnd, name, (NamedEntity) candidate) == CheckResult.FAIL) {
8!
1980
                        return false;
×
1981
                }
1982

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

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

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

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

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

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

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

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

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

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

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

2092

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

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

2117
                // check whether bnd and candidate are already bound
2118
                CheckResult keyMatch = checkKeyMatch(bnd, candidate);
5✔
2119
                if (keyMatch == CheckResult.MATCH) {
3!
2120
                        return true;
×
2121
                } else if (keyMatch == CheckResult.FAIL) {
3✔
2122
                        return false;
2✔
2123
                }
2124

2125
                if (checkNameMatch(bnd, name, candidate) == CheckResult.FAIL) {
7!
2126
                        return false;
×
2127
                }
2128

2129
                // check owner
2130
                TNamedEntity candidateOwner = Util.getOwner(candidate);
3✔
2131

2132
                // local variable or parameter ?
2133
                // owner is a Method? (for example in case of an anonymous class)
2134
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidateOwner);
11✔
2135
                if (res == CheckResult.FAIL) {
3✔
2136
                        return false;
2✔
2137
                } else if (res == CheckResult.MATCH) {
3!
2138
                        conditionalMapToKey(bnd, candidate);
×
2139
                        return true;
×
2140
                }
2141

2142
                // check owner
2143
                // <anArray>.length field?
2144
                if (name.equals("length")) {
4!
2145
                        boolean isArrayLengthField = ((bnd != null) && (bnd.getDeclaringClass() == null)) ||
×
2146
                                                                                 ((bnd == null) && (owner.getName().equals(EntityDictionary.ARRAYS_NAME)));
×
2147
                        if (isArrayLengthField) {
×
2148
                                if (candidateOwner.getName().equals(EntityDictionary.ARRAYS_NAME)) {
×
2149
                                        conditionalMapToKey(bnd, candidate);
×
2150
                                        return true;
×
2151
                                }
2152
                                else {
2153
                                        return false;
×
2154
                                }
2155
                        }
2156
                }
2157

2158
                // check owner
2159
                // "normal" field?
2160
                res = matchAndMapOwnerAsType( ((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2161
                if (res == CheckResult.MATCH) {
3!
2162
                        conditionalMapToKey(bnd, candidate);
4✔
2163
                        return true;
2✔
2164
                }
2165
                return false;
×
2166
        }
2167

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

2179
                // owner is a Method? (for example in case of an anonymous class)
2180
                CheckResult res = matchAndMapOwnerAsMethod(((bnd != null) ? bnd.getDeclaringMethod() : null), owner, candidate);
11✔
2181
                if (res == CheckResult.MATCH) {
3!
2182
                        conditionalMapToKey(bnd, candidate);
×
2183
                        return true;
×
2184
                } else if (res == CheckResult.FAIL) {
3!
2185
                        return false;
×
2186
                }
2187

2188
                // owner is a class ?
2189
                res = matchAndMapOwnerAsType(((bnd != null) ? bnd.getDeclaringClass() : null), owner, candidateOwner);
11✔
2190
                if (res == CheckResult.MATCH) {
3✔
2191
                        conditionalMapToKey(bnd, candidate);
4✔
2192
                        return true;
2✔
2193
                }
2194
                else if (res == CheckResult.FAIL) {
3✔
2195
                        return false;
2✔
2196
                }
2197

2198
                // owner must be a package
2199
                if (matchAndMapOwnerAsNamespace( ((bnd != null)?bnd.getPackage():null), owner, candidateOwner) == CheckResult.MATCH) {
12✔
2200
                        conditionalMapToKey(bnd, candidate);
4✔
2201
                        return true;
2✔
2202
                }
2203
                return false;
2✔
2204
        }
2205

2206
        /**
2207
         * Check whether the owner of candidates is a method macthinf either methBnd or owner
2208
         * @param methBnd
2209
         * @param owner
2210
         * @param candidateOwner
2211
         * @return a {@link CheckResult}
2212
         */
2213
        private  <T extends TNamedEntity> CheckResult matchAndMapOwnerAsMethod(IMethodBinding methBnd, T owner, T candidateOwner) {
2214
                if ((methBnd != null) || ((owner != null) && (owner instanceof Method))) {
7!
2215
                        if (!(candidateOwner instanceof Method)) {
3!
2216
                                return CheckResult.FAIL;
×
2217
                        }
2218

2219
                        ContainerEntity ownerOwner = (owner != null) ? (ContainerEntity) Util.getOwner(owner) : null;
7!
2220
                        String ownerSig = (owner != null) ? ((Method) owner).getSignature() : null;
7!
2221
                        Type ownerReturn = (owner != null) ? (Type) ((Method) owner).getDeclaredType() : null;
8!
2222

2223
                        if (matchAndMapMethod(methBnd, ownerSig, ownerReturn, ownerOwner, (Method) candidateOwner)) {
9!
2224
                                return CheckResult.MATCH;
×
2225
                        } else {
2226
                                return CheckResult.FAIL;
2✔
2227
                        }
2228
                }
2229
                return CheckResult.UNDECIDED;
2✔
2230
        }
2231

2232
        /**
2233
         * @param typBnd
2234
         * @param owner
2235
         * @param candidateOwner
2236
         * @return a {@link CheckResult}
2237
         */
2238
        private CheckResult matchAndMapOwnerAsType(ITypeBinding typBnd, TNamedEntity owner, TNamedEntity candidateOwner) {
2239
                if ((typBnd != null) || ((owner != null) && (owner instanceof Type))) {
7!
2240
                        if (!(candidateOwner instanceof Type)) {
3✔
2241
                                return CheckResult.FAIL;
2✔
2242
                        }
2243

2244
                        TNamedEntity ownerOwner = (owner != null) ? Util.getOwner(owner) : null;
6!
2245
                        String ownerName = (owner != null) ? ((Type) owner).getName() : null;
7!
2246

2247
                        if (matchAndMapType(typBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2248
                                return CheckResult.MATCH;
2✔
2249
                        } else {
2250
                                return CheckResult.FAIL;
2✔
2251
                        }
2252
                }
2253
                return CheckResult.UNDECIDED;
2✔
2254
        }
2255

2256
        private CheckResult matchAndMapOwnerAsNamespace(IPackageBinding pckgBnd, TNamedEntity owner, ContainerEntity candidateOwner) {
2257
                if ((pckgBnd != null) || ((owner != null) && (owner instanceof Package))) {
7!
2258
                        if (!(candidateOwner instanceof Package)) {
3!
2259
                                return CheckResult.FAIL;
×
2260
                        }
2261

2262
                        Package ownerOwner = (owner != null) ? (Package) Util.getOwner(owner) : null;
7!
2263
                        String ownerName = (owner != null) ? ((Package) owner).getName() : null;
7!
2264

2265
                        if (matchAndMapPackage(pckgBnd, ownerName, ownerOwner, candidateOwner)) {
7✔
2266
                                return CheckResult.MATCH;
2✔
2267
                        } else {
2268
                                return CheckResult.FAIL;
2✔
2269
                        }
2270
                }
2271
                return CheckResult.UNDECIDED;
×
2272
        }
2273

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

2294
        /**
2295
         * Check whether key and candidate are already bound together, whether either is bound to something else, or whether none is bound
2296
         * @param key
2297
         * @param candidate
2298
         * @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>
2299
         */
2300
        private CheckResult checkKeyMatch(IBinding key, TNamedEntity candidate) {
2301
                if (key == null) {
2✔
2302
                        return CheckResult.UNDECIDED;
2✔
2303
                }
2304

2305
                NamedEntity bound = (NamedEntity)getEntityByKey(key);
5✔
2306
                if (bound == candidate) {
3✔
2307
                        return CheckResult.MATCH;
2✔
2308
                }
2309
                else if (bound != null) {
2✔
2310
                        return CheckResult.FAIL;
2✔
2311
                }
2312
                else if (getEntityKey(candidate) != null) {
4✔
2313
                        // candidate already bound, and not to this binding
2314
                        return CheckResult.FAIL;
2✔
2315
                }
2316
                else {
2317
                        return CheckResult.UNDECIDED;
2✔
2318
                }
2319
        }
2320

2321
        private void conditionalMapToKey(IBinding bnd, TNamedEntity ent) {
2322
                if (bnd != null) {
2✔
2323
                        mapEntityToKey(bnd, ent);
4✔
2324
                }
2325
        }
1✔
2326

2327
        public Method ensureFamixMethod(IMethodBinding bnd) {
2328
                return ensureFamixMethod(
9✔
2329
                                bnd,
2330
                                /*name*/null,
2331
                                /*paramsType*/(Collection<String>)null,
2332
                                /*returnType*/null,
2333
                                /*owner*/null,
2334
                                (bnd == null) ? UNKNOWN_MODIFIERS : bnd.getModifiers());
6✔
2335
        }
2336

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

2350
                // --------------- to avoid useless computations if we can
2351
                fmx = (Method)getEntityByKey(bnd);
5✔
2352
                if (fmx != null) {
2✔
2353
                        return fmx;
2✔
2354
                }
2355

2356
                // --------------- name
2357
                if (name == null) {
2✔
2358
                        if (bnd == null) {
2✔
2359
                                return null;
2✔
2360
                        }
2361
                        else {
2362
                                name = bnd.getName();
3✔
2363
                        }
2364
                }
2365

2366
                // --------------- signature
2367
                sig = name + "(";
3✔
2368
                 if (bnd != null) {
2✔
2369
                    sig += signatureParamsFromBinding(bnd);
7✔
2370
                }
2371
        else if (paramTypes != null) {
2!
2372
                        sig += signatureParamsFromStringCollection(paramTypes);
7✔
2373
                }
2374
                else {
2375
                        sig += "???";
×
2376
                }
2377
                sig += ")";
3✔
2378

2379
                // --------------- return type
2380
                delayedRetTyp = false;
2✔
2381
                ITypeBinding retTypBnd = null;
2✔
2382
                if (ret == null) {
2!
2383
                        if (bnd == null) {
2✔
2384
                                ret = null;  // what else ?
3✔
2385
                        }
2386
                        else {
2387
                                if (bnd.isConstructor()) {
3✔
2388
                                        ret = null;
3✔
2389
                                }
2390
                                else {
2391

2392
                                        // must create the return type
2393
                                        // but for method like "<T> T mtd()" where T belongs to mtd and mtd returns T,
2394
                                        // we need T to create the method and the method to create T ...
2395
                                        // so we need to test the situation and deal with it
2396
                                        retTypBnd = bnd.getReturnType();
3✔
2397
                                        if (retTypBnd == null) {
2✔
2398
                                                ret = null;
3✔
2399
                                        }
2400
                                        else if (retTypBnd.isArray()) {
3✔
2401
                                                retTypBnd = retTypBnd.getElementType();
3✔
2402
                                        }
2403

2404
                                        if ( (retTypBnd != null) && retTypBnd.isTypeVariable() && (retTypBnd.getDeclaringMethod() == bnd) ) {
9✔
2405
                                                ret = null;
2✔
2406
                                                delayedRetTyp = true;
3✔
2407
                                        }
2408
                                        else {
2409
                                                ret = this.ensureFamixType(retTypBnd,(TWithTypes) /*ctxt*/owner);
6✔
2410
                                        }
2411
                                }
2412
                        }
2413
                }
2414

2415
                // --------------- owner
2416
                if (owner == null) {
2✔
2417
                        if (bnd == null) {
2✔
2418
                                owner = ensureFamixClassStubOwner();
4✔
2419
                        }
2420
                        else {
2421
                                ITypeBinding classBnd = bnd.getDeclaringClass().getErasure();
4✔
2422
                                if (classBnd != null) {
2!
2423
                                        TType tmpOwn = ensureFamixType(classBnd);
4✔
2424

2425
                                        owner = (TWithMethods) tmpOwn;
3✔
2426
                                        
2427
                                }
1✔
2428
                                else {
2429
                                        owner = ensureFamixClassStubOwner();
×
2430
                                }
2431
                        }
2432
                }
2433

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

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

2462
                if (fmx != null) {
2!
2463
                        setMethodModifiers(fmx, modifiers);
4✔
2464
                        // if it's a constructor
2465
                        if (fmx.getName().equals(Util.getOwner(fmx).getName())) {
7✔
2466
                                fmx.setKind(CONSTRUCTOR_KIND_MARKER);
3✔
2467
                        }
2468
                }
2469

2470
                if ((fmx != null) && delayedRetTyp) {
4!
2471
                        int retTypModifiers = (retTypBnd != null) ? retTypBnd.getModifiers() : UNKNOWN_MODIFIERS;
6!
2472
                        ITypeBinding returnTypeBnd = (bnd == null) ? null : bnd.getReturnType();
5!
2473
                        ensureFamixEntityTyping(returnTypeBnd, fmx, this.ensureFamixType(retTypBnd, /*name*/null, /*owner*/fmx, /*ctxt*/(ContainerEntity) owner, retTypModifiers));
13✔
2474
                }
2475

2476
                return fmx;
2✔
2477
        }
2478

2479
        /**
2480
         * Creates or recovers a stub Famix Method
2481
         * @param name of the method
2482
         * @return the Famix Method
2483
         */
2484
        public Method ensureFamixStubMethod(String name) {
2485
                return ensureFamixMethod(null, name, /*paramType*/(Collection<String>)null, /*returnType*/null, ensureFamixClassStubOwner(), /*modifiers*/0);  // cast needed to desambiguate the call
×
2486
        }
2487

2488
        public void setAttributeModifiers(Attribute fmx, int mod) {
2489
                setCommonModifiers(fmx, mod);
4✔
2490
                fmx.setIsTransient(Modifier.isTransient(mod));
5✔
2491
                fmx.setIsVolatile(Modifier.isVolatile(mod));
5✔
2492
        }
1✔
2493

2494
        public void setMethodModifiers(Method fmx, int mod) {
2495
                setCommonModifiers(fmx, mod);
4✔
2496
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2497
                fmx.setIsSynchronized(Modifier.isSynchronized(mod));
5✔
2498
        }
1✔
2499

2500
        public void setClassModifiers(Class fmx, int mod) {
2501
                setCommonModifiers(fmx, mod);
4✔
2502
                fmx.setIsAbstract(Modifier.isAbstract(mod));
5✔
2503
        }
1✔
2504

2505
        public void setInterfaceModifiers(Interface fmx, int mod) {
2506
                setCommonModifiers(fmx, mod);
4✔
2507
        }
1✔
2508

2509
        private void setCommonModifiers(Entity fmx, int mod) {
2510
                setVisibility((THasVisibility)fmx, mod);
5✔
2511
                ((TCanBeClassSide)fmx).setIsClassSide(Modifier.isStatic(mod));
6✔
2512
                ((TCanBeFinal)fmx).setIsFinal(Modifier.isFinal(mod));
6✔
2513
        }
1✔
2514

2515
        /**
2516
         * Sets the visibility of a FamixNamedEntity
2517
         *
2518
         * @param fmx -- the FamixNamedEntity
2519
         * @param mod -- a description of the modifiers as understood by org.eclipse.jdt.core.dom.Modifier
2520
         */
2521
        public void setVisibility(THasVisibility fmx, int mod) {
2522
                if (Modifier.isPublic(mod)) {
3✔
2523
                        fmx.setVisibility(MODIFIER_PUBLIC);
4✔
2524
                } else if (Modifier.isPrivate(mod)) {
3✔
2525
                        fmx.setVisibility(MODIFIER_PRIVATE);
4✔
2526
                } else if (Modifier.isProtected(mod)) {
3✔
2527
                        fmx.setVisibility(MODIFIER_PROTECTED);
4✔
2528
                } else {
2529
                        fmx.setVisibility(MODIFIER_PACKAGE);
3✔
2530
                }
2531
        }
1✔
2532

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

2544
                // --------------- to avoid useless computations if we can
2545
                fmx = (Attribute)getEntityByKey(bnd);
5✔
2546
                if (fmx != null) {
2✔
2547
                        return fmx;
2✔
2548
                }
2549

2550
                // --------------- name
2551
                if (name == null) {
2!
2552
                        if (bnd == null) {
×
2553
                                return null;
×
2554
                        }
2555
                        else {
2556
                                name = bnd.getName();
×
2557
                        }
2558
                }
2559

2560
                // --------------- owner
2561
                if (owner == null) {
2✔
2562
                        if (bnd == null) {
2!
2563
                                return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
×
2564
                        }
2565
                        else {
2566
                                if (bnd.getDeclaringClass() != null && bnd.getDeclaringClass().getErasure() != null) {
7!
2567
                                        // Declaring class is the generic one if the class is parametric.
2568
                                        owner = (TWithAttributes)ensureFamixType(bnd.getDeclaringClass().getErasure());
8✔
2569
                                } else {
2570
                                        return null;  // what would be the interest of creating an attribute for which we ignore the declaring class?
2✔
2571
                                }
2572
                        }
2573
                }
2574

2575
                // --------------- recover from name ?
2576
                for (Attribute candidate : getEntityByName(Attribute.class, name)) {
13✔
2577
                        if (matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate)) {
8✔
2578
                                fmx = candidate;
2✔
2579
                                break;
1✔
2580
                        }
2581
                }
1✔
2582

2583
                if (fmx == null) {
2✔
2584
                        fmx = ensureFamixEntity(Attribute.class, bnd, name);
7✔
2585
                        fmx.setParentType( owner);
3✔
2586
                }
2587

2588
                if (fmx != null) {
2!
2589
                        fmx.setParentType((TWithAttributes) owner);
3✔
2590
                        ITypeBinding declaredTypeBinding = (bnd == null) ? null : bnd.getType();
7✔
2591
                        ensureFamixEntityTyping(declaredTypeBinding, fmx, type);
6✔
2592
                        if (bnd != null) {
2✔
2593
                                int mod = bnd.getModifiers();
3✔
2594
                                setAttributeModifiers(fmx, mod);
4✔
2595
                        }
2596
                }
2597

2598
                return fmx;
2✔
2599
        }
2600

2601
        public Attribute ensureFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2602
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2603
        }
2604

2605
        /**
2606
         * helper method, we know the var exists, ensureFamixAttribute will recover it
2607
         */
2608
        public Attribute getFamixAttribute(IVariableBinding bnd, String name, TWithAttributes owner) {
2609
                return ensureFamixAttribute(bnd, name, /*declared type*/null, owner);
7✔
2610
        }
2611

2612
        /**
2613
         * Returns a Famix Parameter associated with the IVariableBinding.
2614
         * The Entity is created if it does not exist.<br>
2615
         * @return the Famix Entity found or created. May return null if "bnd" is null or in case of a Famix error
2616
         */
2617
        public Parameter ensureFamixParameter(IVariableBinding bnd, String name, Type typ, TMethod tMethod) {
2618
                Parameter fmx = null;
2✔
2619

2620
                // --------------- to avoid useless computations if we can
2621
                try {
2622
                        fmx = (Parameter)getEntityByKey(bnd);
5✔
2623

2624
                }catch(Throwable e) {
×
2625
                        e.printStackTrace();
×
2626
                }
1✔
2627
                if (fmx != null) {
2✔
2628
                        return fmx;
2✔
2629
                }
2630

2631
                // --------------- name
2632
                if (name == null) {
2!
2633
                        if (bnd == null) {
×
2634
                                return null;
×
2635
                        }
2636
                        else {
2637
                                name = bnd.getName();
×
2638
                        }
2639
                }
2640

2641
                // --------------- owner
2642
                if (tMethod == null) {
2!
2643
                        if (bnd == null) {
×
2644
                                tMethod = ensureFamixStubMethod("<"+name+"_owner>");
×
2645
                        }
2646
                        else {
2647
                                tMethod = ensureFamixMethod(bnd.getDeclaringMethod());
×
2648
                        }
2649
                }
2650

2651
                // --------------- recover from name ?
2652
                for (Parameter candidate : getEntityByName(Parameter.class, name) ) {
13✔
2653
                        if ( matchAndMapVariable(bnd, name, tMethod, candidate) ) {
7!
2654
                                fmx = candidate;
×
2655
                                break;
×
2656
                        }
2657
                }
1✔
2658

2659
                if (fmx == null) {
2!
2660
                        fmx = ensureFamixEntity(Parameter.class, bnd, name);
7✔
2661
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2662
                }
2663

2664
                if (fmx != null) {
2!
2665
                        fmx.setParentBehaviouralEntity(tMethod);
3✔
2666
                        ITypeBinding declaredTypeBnd = (bnd == null) ? null : bnd.getType();
5!
2667
                        ensureFamixEntityTyping(declaredTypeBnd, fmx, typ);
6✔
2668
                }
2669

2670
                return fmx;
2✔
2671
        }
2672

2673
        /**
2674
         * helper method, we know the var exists, ensureFamixParameter will recover it
2675
         */
2676
        public Parameter getFamixParameter(IVariableBinding bnd, String name, TMethod tMethod) {
2677
                return ensureFamixParameter(bnd, name, /*declared type*/null, tMethod);
×
2678
        }
2679

2680
        /**
2681
         * Returns a Famix LocalVariable associated with the IVariableBinding.
2682
         * The Entity is created if it does not exist.<br>
2683
         * @param name -- the name of the FAMIX LocalVariable
2684
         * @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
2685
         */
2686
        public LocalVariable ensureFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2687
                LocalVariable fmx = null;
2✔
2688

2689
                // --------------- to avoid useless computations if we can
2690
                fmx = (LocalVariable)getEntityByKey(bnd);
5✔
2691
                if (fmx != null) {
2!
2692
                        return fmx;
×
2693
                }
2694

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

2705
                // --------------- owner
2706
                if (owner == null) {
2!
2707
                        if (bnd == null) {
×
2708
                                return null;  // what would be the interest of a local variable for which we ignore the declaring method?
×
2709
                        }
2710
                        else {
2711
                                owner = ensureFamixMethod(bnd.getDeclaringMethod());
×
2712
                        }
2713
                }
2714

2715
                // --------------- recover from name ?
2716
                for (LocalVariable candidate : getEntityByName(LocalVariable.class, name) ) {
13✔
2717
                        if ( matchAndMapVariable(bnd, name, (TNamedEntity) owner, candidate) ) {
8!
2718
                                fmx = candidate;
×
2719
                                break;
×
2720
                        }
2721
                }
1✔
2722

2723
                if (fmx == null) {
2!
2724
                        fmx = ensureFamixEntity(LocalVariable.class, bnd, name);
7✔
2725
                        fmx.setParentBehaviouralEntity(owner);
3✔
2726
                }
2727

2728
                if (fmx != null) {
2!
2729
                        // we just created it or it was not bound, so we make sure it has the right information in it
2730
                        fmx.setParentBehaviouralEntity(owner);
3✔
2731
                }
2732

2733
                return fmx;
2✔
2734
        }
2735

2736
        /**
2737
         * helper method, we know the var exists, ensureFamixLocalVariable will recover it
2738
         */
2739
        public LocalVariable getFamixLocalVariable(IVariableBinding bnd, String name, TWithLocalVariables owner) {
2740
                return ensureFamixLocalVariable(bnd, name, owner);
×
2741
        }
2742

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

2758
        public ImplicitVariable ensureFamixImplicitVariable(String name, TType tType, TMethod tMethod) {
2759
                IBinding bnd = ImplicitVarBinding.getInstance(tMethod, name);
4✔
2760
                return ensureFamixImplicitVariable(bnd, name, tType, tMethod);
7✔
2761
        }
2762

2763
        /**
2764
         * Creates and returns a Famix Comment and associates it with an Entity (ex: for Javadocs)
2765
         * @param jCmt -- the content (String) of the comment 
2766
         * @param owner -- the entity that is commented
2767
         * @return the Famix Comment
2768
         */
2769
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner) {
2770
                Comment cmt = null;
2✔
2771

2772
                if ( (jCmt != null) && (owner != null) ) {
4!
2773
                        
2774
                        cmt = new Comment();
4✔
2775
                        addSourceAnchor(cmt, jCmt);
5✔
2776
                        famixRepoAdd(cmt);
3✔
2777
                        cmt.setCommentedEntity(owner);
3✔
2778
                }
2779

2780
                return cmt;
2✔
2781
        }
2782

2783
        /**
2784
         * Creates and returns a Famix Comment and associates it with an Entity
2785
         * @param jCmt -- the content (String) of the comment 
2786
         * @param owner -- the entity that is commented
2787
         * @param content -- the text of the comment
2788
         * @return the Famix Comment
2789
         */
2790
        public Comment createFamixComment(org.eclipse.jdt.core.dom.Comment jCmt, TWithComments owner, String content) {
2791
                Comment cmt = null;
2✔
2792

2793
                if ( (jCmt != null) && (owner != null) ) {
4!
2794
                        cmt = new Comment();
4✔
2795
                        cmt.setContent(content );
3✔
2796
                        famixRepoAdd(cmt);
3✔
2797
                        cmt.setCommentedEntity(owner);
3✔
2798
                }
2799

2800
                return cmt;
2✔
2801
        }
2802

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

2814
                fa = createIndexedFileAnchor(node);
4✔
2815
                if ((fmx != null) && (fa != null)) {
4!
2816
                        fmx.setSourceAnchor(fa);
3✔
2817
                        famixRepoAdd(fa);
3✔
2818
                }
2819

2820
                return fa;
2✔
2821
        }
2822

2823
        /**
2824
         * Special case of  {@linkplain #addSourceAnchor(TSourceEntity, ASTNode)} to add location information to a Famix Method.
2825
         */
2826
        public SourceAnchor addSourceAnchor(Method fmx, MethodDeclaration node) {
2827
                IndexedFileAnchor fa = null;
2✔
2828

2829
                fa = createIndexedFileAnchor(node);
4✔
2830
                if ((fmx != null) && (fa != null)) {
4!
2831

2832
                        // may change the positions
2833
                        List<ASTNode> methodDeclarationModifiers = new ArrayList<>();
4✔
2834
                        methodDeclarationModifiers.addAll(node.modifiers());
5✔
2835
                        if (node.getName() != null) {
3!
2836
                                methodDeclarationModifiers.add(node.getName());
5✔
2837
                        }
2838
                        if (node.getReturnType2() != null) {
3✔
2839
                                methodDeclarationModifiers.add(node.getReturnType2());
5✔
2840
                        }
2841
                        int beg = (methodDeclarationModifiers.stream().mapToInt(el -> el.getStartPosition()).min().getAsInt()) + 1;
12✔
2842
                        int end = node.getStartPosition() + node.getLength();
6✔
2843

2844
                        ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2845
                        ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2846

2847
                        fmx.setSourceAnchor(fa);
3✔
2848
                        famixRepoAdd(fa);
3✔
2849
                }
2850

2851
                return fa;
2✔
2852
        }
2853

2854
        /**
2855
         * Gets the file name holding <code>node</code> and its start and end positions in the file.
2856
         * Information returned in the form of an IndexedFileAnchor
2857
         */
2858
        protected IndexedFileAnchor createIndexedFileAnchor(ASTNode node) {
2859
                IndexedFileAnchor fa;
2860
                
2861
                if (node == null) {
2!
2862
                        return null;
×
2863
                }
2864

2865
                // position in source file
2866
                int beg = node.getStartPosition() + 1; // Java starts at 0, Moose at 1
5✔
2867
                int end = beg + node.getLength() - 1;
7✔
2868

2869
                // find source Compilation Unit
2870
                // there is a special case for the JDT Comment Nodes
2871
                if (node instanceof org.eclipse.jdt.core.dom.Comment) {
3✔
2872
                        node = ((org.eclipse.jdt.core.dom.Comment) node).getAlternateRoot();
5✔
2873
                } else {
2874
                        node = node.getRoot();
3✔
2875
                }
2876

2877
                fa = new IndexedFileAnchor();
4✔
2878
                ((IndexedFileAnchor)fa).setStartPos(beg);
4✔
2879
                ((IndexedFileAnchor)fa).setEndPos(end);
4✔
2880

2881
                fa.setFileName((String) ((CompilationUnit)node).getProperty(SOURCE_FILENAME_PROPERTY));
7✔
2882

2883
                return fa;
2✔
2884
        }
2885

2886
        /**
2887
         * Creates or recovers the Famix Class for "Object".
2888
         * Because "Object" is the root of the inheritance tree, it needs to be treated differently.
2889
         *
2890
         * @param bnd -- a potential binding for the java "Object" class
2891
         * @return a Famix class for "Object"
2892
         */
2893
        public Class ensureFamixClassObject(ITypeBinding bnd) {
2894
                Class fmx = ensureFamixUniqEntity(Class.class, bnd, OBJECT_NAME);
7✔
2895

2896
                if (fmx != null) {
2!
2897
                        fmx.setTypeContainer(ensureFamixPackageJavaLang(null));
5✔
2898
                }
2899
                // Note: "Object" has no superclass
2900

2901
                return fmx;
2✔
2902
        }
2903

2904
        /**
2905
         * Ensures the Java meta-class: <pre>{@code java.lang.Class<>}</pre>
2906
         */
2907
        public Class ensureFamixMetaClass(ITypeBinding bnd) {
2908
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2909
                ParametricClass fmx = (ParametricClass) this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, Modifier.PUBLIC & Modifier.FINAL);
9✔
2910

2911
                if (fmx != null) {
2!
2912
                        fmx.addTypeParameters(ensureFamixTypeParameter(null, "T", fmx));
7✔
2913
                }
2914

2915
                if ((fmx != null) && (fmx.getSuperInheritances() == null)) {
5!
NEW
2916
                        ensureFamixInheritance(ensureFamixClassObject(null), fmx, null, null);
×
2917
                }
2918

2919
                return fmx;
2✔
2920
        }
2921

2922
        public Class getFamixMetaClass(ITypeBinding bnd) {
2923
                Package javaLang = ensureFamixPackageJavaLang((bnd == null) ? null : bnd.getPackage());
7!
2924
                return this.ensureFamixClass(null, METACLASS_NAME, javaLang, /*isGeneric*/true, UNKNOWN_MODIFIERS);
8✔
2925
        }
2926

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

2940
                        // may be not needed anymore now that we use modifiers
2941
                        /*fmx.setIsAbstract(Boolean.FALSE);
2942
                        fmx.setIsFinal(Boolean.FALSE);
2943
                        fmx.setIsInterface(Boolean.FALSE); 
2944
                        fmx.setIsPrivate(Boolean.FALSE);
2945
                        fmx.setIsProtected(Boolean.FALSE);*/
2946
                        fmx.setVisibility(MODIFIER_PUBLIC);
×
2947
                }
2948

2949
                return fmx;
×
2950
        }
2951

2952
        public String removeLastPartOfPackageName(String qualifiedName) {
2953
                String ret = null;
2✔
2954
                int last = qualifiedName.lastIndexOf('.');
4✔
2955
                if (last > 0) {
2✔
2956
                        // recursively creating the parent
2957
                        ret = qualifiedName.substring(0, last);
6✔
2958
                }
2959
                else {
2960
                        ret = "";
2✔
2961
                }
2962

2963
                return ret;
2✔
2964
        }
2965

2966
        /** Generates the list of parameters for a method signature
2967
         * @return a string
2968
         */
2969
        protected String signatureParamsFromBinding(IMethodBinding bnd) {
2970
                boolean first = true;
2✔
2971
                String sig = new String();
4✔
2972

2973
                for (ITypeBinding parBnd : bnd.getParameterTypes()) {
17✔
2974
                        if (first) {
2✔
2975
                                sig = parBnd.getName();
3✔
2976
                                first = false;
3✔
2977
                        }
2978
                        else {
2979
                                sig += "," + parBnd.getName();
5✔
2980
                        }
2981
                }
2982
                return sig;
2✔
2983
        }
2984

2985
        private String signatureParamsFromStringCollection(Collection<String> paramTypes) {
2986
                boolean first = true;
2✔
2987
                String sig = new String();
4✔
2988

2989
                for (String t : paramTypes) {
10✔
2990
                        if (first) {
2✔
2991
                                sig = t;
2✔
2992
                                first = false;
3✔
2993
                        }
2994
                        else {
2995
                                sig += "," + t;
4✔
2996
                        }
2997
                }
1✔
2998
                return sig;
2✔
2999
        }
3000

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

© 2026 Coveralls, Inc