ts2famix 1.4.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/analyze.js +4 -2
- package/dist/analyze_functions/process_functions.js +248 -100
- package/dist/famix2puml.js +1 -0
- package/dist/famix_functions/EntityDictionary.js +661 -155
- package/dist/famix_functions/helpers_creation.js +26 -6
- package/dist/fqn.js +156 -69
- package/dist/lib/famix/src/famix_JSON_exporter.js +1 -0
- package/dist/lib/famix/src/famix_base_element.js +1 -0
- package/dist/lib/famix/src/famix_repository.js +9 -8
- package/dist/lib/famix/src/index.js +1 -0
- package/dist/lib/famix/src/model/famix/access.js +3 -2
- package/dist/lib/famix/src/model/famix/accessor.js +1 -0
- package/dist/lib/famix/src/model/famix/alias.js +2 -1
- package/dist/lib/famix/src/model/famix/arrowFunction.js +17 -0
- package/dist/lib/famix/src/model/famix/behavioral_entity.js +13 -15
- package/dist/lib/famix/src/model/famix/class.js +1 -0
- package/dist/lib/famix/src/model/famix/comment.js +2 -1
- package/dist/lib/famix/src/model/famix/concretisation.js +31 -0
- package/dist/lib/famix/src/model/famix/container_entity.js +7 -6
- package/dist/lib/famix/src/model/famix/decorator.js +2 -1
- package/dist/lib/famix/src/model/famix/entity.js +1 -0
- package/dist/lib/famix/src/model/famix/enum.js +2 -1
- package/dist/lib/famix/src/model/famix/enum_value.js +2 -1
- package/dist/lib/famix/src/model/famix/function.js +1 -0
- package/dist/lib/famix/src/model/famix/implicit_variable.js +1 -0
- package/dist/lib/famix/src/model/famix/import_clause.js +5 -3
- package/dist/lib/famix/src/model/famix/index.js +18 -11
- package/dist/lib/famix/src/model/famix/indexed_file_anchor.js +3 -2
- package/dist/lib/famix/src/model/famix/inheritance.js +3 -2
- package/dist/lib/famix/src/model/famix/interface.js +2 -1
- package/dist/lib/famix/src/model/famix/invocation.js +3 -2
- package/dist/lib/famix/src/model/famix/method.js +2 -1
- package/dist/lib/famix/src/model/famix/module.js +53 -0
- package/dist/lib/famix/src/model/famix/named_entity.js +4 -3
- package/dist/lib/famix/src/model/famix/parameter.js +2 -1
- package/dist/lib/famix/src/model/famix/parameterConcretisation.js +44 -0
- package/dist/lib/famix/src/model/famix/parameter_type.js +22 -1
- package/dist/lib/famix/src/model/famix/parametric_arrow_function.js +31 -0
- package/dist/lib/famix/src/model/famix/parametric_class.js +44 -0
- package/dist/lib/famix/src/model/famix/parametric_function.js +31 -0
- package/dist/lib/famix/src/model/famix/parametric_interface.js +44 -0
- package/dist/lib/famix/src/model/famix/parametric_method.js +31 -0
- package/dist/lib/famix/src/model/famix/primitive_type.js +1 -0
- package/dist/lib/famix/src/model/famix/property.js +91 -9
- package/dist/lib/famix/src/model/famix/reference.js +3 -2
- package/dist/lib/famix/src/model/famix/scoping_entity.js +12 -10
- package/dist/lib/famix/src/model/famix/script_entity.js +1 -2
- package/dist/lib/famix/src/model/famix/source_anchor.js +1 -0
- package/dist/lib/famix/src/model/famix/source_language.js +1 -1
- package/dist/lib/famix/src/model/famix/sourced_entity.js +2 -1
- package/dist/lib/famix/src/model/famix/structural_entity.js +1 -0
- package/dist/lib/famix/src/model/famix/text_anchor.js +1 -0
- package/dist/lib/famix/src/model/famix/type.js +6 -4
- package/dist/lib/famix/src/model/famix/variable.js +1 -0
- package/dist/lib/ts-complex/cyclomatic-service.js +2 -2
- package/dist/ts2famix-cli-wrapper.js +16 -0
- package/dist/ts2famix-cli.js +8 -1
- package/dist/ts2famix-tsconfig.js +1 -0
- package/doc-uml/famix-typescript-model.puml +559 -0
- package/doc-uml/famix-typescript-model.svg +1 -0
- package/jest.config.json +2 -1
- package/package.json +10 -10
- package/src/analyze.ts +22 -21
- package/src/analyze_functions/process_functions.ts +272 -96
- package/src/famix_functions/EntityDictionary.ts +731 -182
- package/src/famix_functions/helpers_creation.ts +28 -2
- package/src/fqn.ts +132 -10
- package/src/lib/famix/src/famix_repository.ts +9 -9
- package/src/lib/famix/src/model/famix/access.ts +2 -2
- package/src/lib/famix/src/model/famix/alias.ts +1 -1
- package/src/lib/famix/src/model/famix/arrowFunction.ts +15 -0
- package/src/lib/famix/src/model/famix/behavioral_entity.ts +12 -19
- package/src/lib/famix/src/model/famix/comment.ts +1 -1
- package/src/lib/famix/src/model/famix/concretisation.ts +42 -0
- package/src/lib/famix/src/model/famix/container_entity.ts +6 -6
- package/src/lib/famix/src/model/famix/decorator.ts +1 -1
- package/src/lib/famix/src/model/famix/enum.ts +1 -1
- package/src/lib/famix/src/model/famix/enum_value.ts +1 -1
- package/src/lib/famix/src/model/famix/import_clause.ts +4 -3
- package/src/lib/famix/src/model/famix/index.ts +8 -5
- package/src/lib/famix/src/model/famix/indexed_file_anchor.ts +2 -2
- package/src/lib/famix/src/model/famix/inheritance.ts +3 -4
- package/src/lib/famix/src/model/famix/interface.ts +1 -1
- package/src/lib/famix/src/model/famix/invocation.ts +2 -2
- package/src/lib/famix/src/model/famix/method.ts +1 -1
- package/src/lib/famix/src/model/famix/module.ts +67 -1
- package/src/lib/famix/src/model/famix/named_entity.ts +3 -3
- package/src/lib/famix/src/model/famix/parameter.ts +1 -1
- package/src/lib/famix/src/model/famix/parameterConcretisation.ts +54 -0
- package/src/lib/famix/src/model/famix/parameter_type.ts +33 -6
- package/src/lib/famix/src/model/famix/parametric_arrow_function.ts +32 -0
- package/src/lib/famix/src/model/famix/parametric_class.ts +49 -0
- package/src/lib/famix/src/model/famix/parametric_function.ts +32 -0
- package/src/lib/famix/src/model/famix/parametric_interface.ts +49 -0
- package/src/lib/famix/src/model/famix/parametric_method.ts +32 -0
- package/src/lib/famix/src/model/famix/property.ts +109 -11
- package/src/lib/famix/src/model/famix/reference.ts +2 -2
- package/src/lib/famix/src/model/famix/scoping_entity.ts +12 -11
- package/src/lib/famix/src/model/famix/script_entity.ts +0 -2
- package/src/lib/famix/src/model/famix/source_language.ts +0 -1
- package/src/lib/famix/src/model/famix/sourced_entity.ts +1 -1
- package/src/lib/famix/src/model/famix/type.ts +5 -4
- package/src/ts2famix-cli-wrapper.ts +17 -0
- package/src/ts2famix-cli.ts +7 -1
- package/tsconfig.json +5 -5
- package/dist/lib/famix/src/model/famix/association.js +0 -36
- package/dist/lib/famix/src/model/famix/namespace.js +0 -24
- package/dist/lib/famix/src/model/famix/parameterizable_class.js +0 -30
- package/dist/lib/famix/src/model/famix/parameterizable_interface.js +0 -30
- package/dist/lib/famix/src/model/famix/parameterized_type.js +0 -36
- package/doc-uml/metamodel-full.svg +0 -1
- package/doc-uml/metamodel.svg +0 -1
- package/plantuml.jar +0 -0
- package/src/lib/famix/src/model/famix/association.ts +0 -44
- package/src/lib/famix/src/model/famix/namespace.ts +0 -28
- package/src/lib/famix/src/model/famix/parameterizable_class.ts +0 -31
- package/src/lib/famix/src/model/famix/parameterizable_interface.ts +0 -31
- package/src/lib/famix/src/model/famix/parameterized_type.ts +0 -40
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ClassDeclaration, ConstructorDeclaration, FunctionDeclaration, Identifier, InterfaceDeclaration, MethodDeclaration, MethodSignature, ModuleDeclaration, PropertyDeclaration, PropertySignature, SourceFile, TypeParameterDeclaration, VariableDeclaration, ParameterDeclaration, Decorator, GetAccessorDeclaration, SetAccessorDeclaration, ImportSpecifier, CommentRange, EnumDeclaration, EnumMember, TypeAliasDeclaration, FunctionExpression, ExpressionWithTypeArguments, ImportDeclaration, ImportEqualsDeclaration } from "ts-morph";
|
|
1
|
+
import { ClassDeclaration, ConstructorDeclaration, FunctionDeclaration, Identifier, InterfaceDeclaration, MethodDeclaration, MethodSignature, ModuleDeclaration, PropertyDeclaration, PropertySignature, SourceFile, TypeParameterDeclaration, VariableDeclaration, ParameterDeclaration, Decorator, GetAccessorDeclaration, SetAccessorDeclaration, ImportSpecifier, CommentRange, EnumDeclaration, EnumMember, TypeAliasDeclaration, FunctionExpression, ExpressionWithTypeArguments, ImportDeclaration, ImportEqualsDeclaration, SyntaxKind, Expression, TypeNode, Node, ts, Scope, Type, ArrowFunction } from "ts-morph";
|
|
2
|
+
import { isAmbient, isNamespace } from "../analyze_functions/process_functions";
|
|
2
3
|
import * as Famix from "../lib/famix/src/model/famix";
|
|
3
4
|
import { logger, config } from "../analyze";
|
|
4
5
|
import GraphemeSplitter from "grapheme-splitter";
|
|
@@ -6,24 +7,27 @@ import * as Helpers from "./helpers_creation";
|
|
|
6
7
|
import * as FQNFunctions from "../fqn";
|
|
7
8
|
import { FamixRepository } from "../lib/famix/src/famix_repository";
|
|
8
9
|
import path from "path";
|
|
10
|
+
import _ from 'lodash';
|
|
9
11
|
|
|
10
12
|
export type TSMorphObjectType = ImportDeclaration | ImportEqualsDeclaration | SourceFile | ModuleDeclaration | ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | FunctionDeclaration | FunctionExpression | ParameterDeclaration | VariableDeclaration | PropertyDeclaration | PropertySignature | TypeParameterDeclaration | Identifier | Decorator | GetAccessorDeclaration | SetAccessorDeclaration | ImportSpecifier | CommentRange | EnumDeclaration | EnumMember | TypeAliasDeclaration | ExpressionWithTypeArguments;
|
|
11
13
|
|
|
14
|
+
export type TypeDeclaration = TypeAliasDeclaration | PropertyDeclaration | PropertySignature | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ParameterDeclaration | VariableDeclaration | EnumMember;
|
|
15
|
+
|
|
12
16
|
export class EntityDictionary {
|
|
13
17
|
|
|
14
18
|
public famixRep = new FamixRepository();
|
|
15
19
|
private fmxAliasMap = new Map<string, Famix.Alias>(); // Maps the alias names to their Famix model
|
|
16
|
-
private fmxClassMap = new Map<string, Famix.Class | Famix.
|
|
17
|
-
private fmxInterfaceMap = new Map<string, Famix.Interface | Famix.
|
|
18
|
-
private
|
|
20
|
+
private fmxClassMap = new Map<string, Famix.Class | Famix.ParametricClass>(); // Maps the fully qualified class names to their Famix model
|
|
21
|
+
private fmxInterfaceMap = new Map<string, Famix.Interface | Famix.ParametricInterface>(); // Maps the interface names to their Famix model
|
|
22
|
+
private fmxModuleMap = new Map<string, Famix.Module>(); // Maps the namespace names to their Famix model
|
|
19
23
|
private fmxFileMap = new Map<string, Famix.ScriptEntity | Famix.Module>(); // Maps the source file names to their Famix model
|
|
20
|
-
private fmxTypeMap = new Map<string, Famix.Type | Famix.PrimitiveType | Famix.
|
|
24
|
+
private fmxTypeMap = new Map<string, Famix.Type | Famix.PrimitiveType | Famix.ParameterType>(); // Maps the type names to their Famix model
|
|
25
|
+
private fmxFunctionAndMethodMap = new Map<string, Famix.Function | Famix.ParametricFunction | Famix.Method | Famix.ParametricMethod> // Maps the function names to their Famix model
|
|
21
26
|
private UNKNOWN_VALUE = '(unknown due to parsing error)'; // The value to use when a name is not usable
|
|
22
27
|
public fmxElementObjectMap = new Map<Famix.Entity,TSMorphObjectType>();
|
|
23
28
|
|
|
24
29
|
constructor() {
|
|
25
|
-
this.famixRep.setFmxElementObjectMap(this.fmxElementObjectMap);
|
|
26
|
-
|
|
30
|
+
this.famixRep.setFmxElementObjectMap(this.fmxElementObjectMap);
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -35,7 +39,7 @@ export class EntityDictionary {
|
|
|
35
39
|
logger.debug("making index file anchor for '" + sourceElement?.getText() + "' with famixElement " + famixElement.getJSON());
|
|
36
40
|
const fmxIndexFileAnchor = new Famix.IndexedFileAnchor();
|
|
37
41
|
fmxIndexFileAnchor.setElement(famixElement);
|
|
38
|
-
this.fmxElementObjectMap.set(famixElement,sourceElement);
|
|
42
|
+
this.fmxElementObjectMap.set(famixElement, sourceElement);
|
|
39
43
|
|
|
40
44
|
if (sourceElement !== null) {
|
|
41
45
|
const absolutePathProject = this.famixRep.getAbsolutePath();
|
|
@@ -102,8 +106,10 @@ export class EntityDictionary {
|
|
|
102
106
|
fmxIndexFileAnchor.setEndLine(sourceLineEnd);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
if (!(famixElement instanceof Famix.
|
|
106
|
-
|
|
109
|
+
if (!(famixElement instanceof Famix.ImportClause || famixElement instanceof Famix.Access || famixElement instanceof Famix.Reference || famixElement instanceof Famix.Invocation || famixElement instanceof Famix.Inheritance) && !(famixElement instanceof Famix.Comment) && !(sourceElement instanceof CommentRange) && !(sourceElement instanceof Identifier) && !(sourceElement instanceof ImportSpecifier) && !(sourceElement instanceof ExpressionWithTypeArguments)) {
|
|
110
|
+
const fqn = FQNFunctions.getFQN(sourceElement);
|
|
111
|
+
logger.debug("Setting fully qualified name for " + famixElement.getJSON() + " to " + fqn);
|
|
112
|
+
(famixElement as Famix.NamedEntity).setFullyQualifiedName(fqn);
|
|
107
113
|
}
|
|
108
114
|
} else {
|
|
109
115
|
// sourceElement is null
|
|
@@ -123,13 +129,13 @@ export class EntityDictionary {
|
|
|
123
129
|
* @returns The Famix model of the source file
|
|
124
130
|
*/
|
|
125
131
|
public createOrGetFamixFile(f: SourceFile, isModule: boolean): Famix.ScriptEntity | Famix.Module {
|
|
126
|
-
let fmxFile: Famix.ScriptEntity | Famix.Module;
|
|
132
|
+
let fmxFile: Famix.ScriptEntity; // | Famix.Module;
|
|
127
133
|
|
|
128
134
|
const fileName = f.getBaseName();
|
|
129
135
|
const fullyQualifiedFilename = f.getFilePath();
|
|
130
136
|
if (!this.fmxFileMap.has(fullyQualifiedFilename)) {
|
|
131
137
|
if (isModule) {
|
|
132
|
-
fmxFile = new Famix.Module();
|
|
138
|
+
fmxFile = new Famix.Module();
|
|
133
139
|
}
|
|
134
140
|
else {
|
|
135
141
|
fmxFile = new Famix.ScriptEntity();
|
|
@@ -152,29 +158,32 @@ export class EntityDictionary {
|
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
/**
|
|
155
|
-
* Creates or gets a Famix
|
|
156
|
-
* @param m A
|
|
157
|
-
* @returns The Famix model of the
|
|
161
|
+
* Creates or gets a Famix Module
|
|
162
|
+
* @param m A module
|
|
163
|
+
* @returns The Famix model of the module
|
|
158
164
|
*/
|
|
159
|
-
public
|
|
160
|
-
let
|
|
161
|
-
const
|
|
162
|
-
if (!this.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
public createOrGetFamixModule(m: ModuleDeclaration): Famix.Module {
|
|
166
|
+
let fmxModule: Famix.Module;
|
|
167
|
+
const moduleName = m.getName();
|
|
168
|
+
if (!this.fmxModuleMap.has(moduleName)) {
|
|
169
|
+
fmxModule = new Famix.Module();
|
|
170
|
+
fmxModule.setName(moduleName);
|
|
171
|
+
fmxModule.$isAmbient = isAmbient(m);
|
|
172
|
+
fmxModule.$isNamespace = isNamespace(m);
|
|
173
|
+
fmxModule.$isModule = !fmxModule.$isNamespace && !fmxModule.$isAmbient;
|
|
165
174
|
|
|
166
|
-
this.makeFamixIndexFileAnchor(m,
|
|
175
|
+
this.makeFamixIndexFileAnchor(m, fmxModule);
|
|
167
176
|
|
|
168
|
-
this.
|
|
177
|
+
this.fmxModuleMap.set(moduleName, fmxModule);
|
|
169
178
|
|
|
170
|
-
this.famixRep.addElement(
|
|
179
|
+
this.famixRep.addElement(fmxModule);
|
|
171
180
|
}
|
|
172
181
|
else {
|
|
173
|
-
|
|
182
|
+
fmxModule = this.fmxModuleMap.get(moduleName);
|
|
174
183
|
}
|
|
175
184
|
|
|
176
|
-
this.fmxElementObjectMap.set(
|
|
177
|
-
return
|
|
185
|
+
this.fmxElementObjectMap.set(fmxModule,m);
|
|
186
|
+
return fmxModule;
|
|
178
187
|
}
|
|
179
188
|
|
|
180
189
|
/**
|
|
@@ -214,15 +223,15 @@ export class EntityDictionary {
|
|
|
214
223
|
* @param cls A class
|
|
215
224
|
* @returns The Famix model of the class
|
|
216
225
|
*/
|
|
217
|
-
public createOrGetFamixClass(cls: ClassDeclaration): Famix.Class | Famix.
|
|
218
|
-
let fmxClass: Famix.Class | Famix.
|
|
226
|
+
public createOrGetFamixClass(cls: ClassDeclaration): Famix.Class | Famix.ParametricClass {
|
|
227
|
+
let fmxClass: Famix.Class | Famix.ParametricClass;
|
|
219
228
|
const isAbstract = cls.isAbstract();
|
|
220
229
|
const classFullyQualifiedName = FQNFunctions.getFQN(cls);
|
|
221
230
|
const clsName = cls.getName();
|
|
231
|
+
const isGeneric = cls.getTypeParameters().length;
|
|
222
232
|
if (!this.fmxClassMap.has(classFullyQualifiedName)) {
|
|
223
|
-
const isGeneric = cls.getTypeParameters().length;
|
|
224
233
|
if (isGeneric) {
|
|
225
|
-
fmxClass = new Famix.
|
|
234
|
+
fmxClass = new Famix.ParametricClass();
|
|
226
235
|
}
|
|
227
236
|
else {
|
|
228
237
|
fmxClass = new Famix.Class();
|
|
@@ -238,13 +247,12 @@ export class EntityDictionary {
|
|
|
238
247
|
|
|
239
248
|
this.famixRep.addElement(fmxClass);
|
|
240
249
|
|
|
250
|
+
this.fmxElementObjectMap.set(fmxClass,cls);
|
|
241
251
|
}
|
|
242
252
|
else {
|
|
243
|
-
fmxClass = this.fmxClassMap.get(classFullyQualifiedName) as (Famix.Class | Famix.
|
|
253
|
+
fmxClass = this.fmxClassMap.get(classFullyQualifiedName) as (Famix.Class | Famix.ParametricClass);
|
|
244
254
|
}
|
|
245
255
|
|
|
246
|
-
this.fmxElementObjectMap.set(fmxClass,cls);
|
|
247
|
-
|
|
248
256
|
return fmxClass;
|
|
249
257
|
}
|
|
250
258
|
|
|
@@ -253,14 +261,14 @@ export class EntityDictionary {
|
|
|
253
261
|
* @param inter An interface
|
|
254
262
|
* @returns The Famix model of the interface
|
|
255
263
|
*/
|
|
256
|
-
public createOrGetFamixInterface(inter: InterfaceDeclaration): Famix.Interface | Famix.
|
|
257
|
-
let fmxInterface: Famix.Interface | Famix.
|
|
264
|
+
public createOrGetFamixInterface(inter: InterfaceDeclaration): Famix.Interface | Famix.ParametricInterface {
|
|
265
|
+
let fmxInterface: Famix.Interface | Famix.ParametricInterface;
|
|
258
266
|
const interName = inter.getName();
|
|
259
267
|
const interFullyQualifiedName = FQNFunctions.getFQN(inter);
|
|
260
|
-
if (!this.fmxInterfaceMap.has(
|
|
268
|
+
if (!this.fmxInterfaceMap.has(interFullyQualifiedName)) {
|
|
261
269
|
const isGeneric = inter.getTypeParameters().length;
|
|
262
270
|
if (isGeneric) {
|
|
263
|
-
fmxInterface = new Famix.
|
|
271
|
+
fmxInterface = new Famix.ParametricInterface();
|
|
264
272
|
}
|
|
265
273
|
else {
|
|
266
274
|
fmxInterface = new Famix.Interface();
|
|
@@ -273,15 +281,71 @@ export class EntityDictionary {
|
|
|
273
281
|
this.fmxInterfaceMap.set(interFullyQualifiedName, fmxInterface);
|
|
274
282
|
|
|
275
283
|
this.famixRep.addElement(fmxInterface);
|
|
284
|
+
|
|
285
|
+
this.fmxElementObjectMap.set(fmxInterface,inter);
|
|
276
286
|
}
|
|
277
287
|
else {
|
|
278
|
-
fmxInterface = this.fmxInterfaceMap.get(
|
|
288
|
+
fmxInterface = this.fmxInterfaceMap.get(interFullyQualifiedName) as (Famix.Interface | Famix.ParametricInterface);
|
|
279
289
|
}
|
|
280
|
-
|
|
281
|
-
this.fmxElementObjectMap.set(fmxInterface,inter);
|
|
282
290
|
return fmxInterface;
|
|
283
291
|
}
|
|
284
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Creates or gets a Famix concrete element
|
|
295
|
+
* @param el A parametric Element
|
|
296
|
+
* @param elDeclaration the element declaration
|
|
297
|
+
* @param concreteArguments concrete arguments
|
|
298
|
+
* @returns A parametric Element
|
|
299
|
+
*/
|
|
300
|
+
public createOrGetFamixConcreteElement(el : Famix.ParametricClass | Famix.ParametricInterface | Famix.ParametricFunction | Famix.ParametricMethod, elDeclaration : ClassDeclaration | InterfaceDeclaration | FunctionDeclaration | MethodDeclaration, concreteArguments : any): Famix.ParametricClass | Famix.ParametricInterface | Famix.ParametricFunction | Famix.ParametricMethod {
|
|
301
|
+
|
|
302
|
+
let fullyQualifiedFilename = el.getFullyQualifiedName();
|
|
303
|
+
let params = "";
|
|
304
|
+
|
|
305
|
+
concreteArguments.map((param) => {
|
|
306
|
+
params = params+param.getText()+','
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
params = params.substring(0, params.length - 1)
|
|
310
|
+
|
|
311
|
+
fullyQualifiedFilename = Helpers.replaceLastBetweenTags(fullyQualifiedFilename,params);
|
|
312
|
+
|
|
313
|
+
let concElement;
|
|
314
|
+
|
|
315
|
+
if (!this.fmxInterfaceMap.has(fullyQualifiedFilename) && !this.fmxClassMap.has(fullyQualifiedFilename) && !this.fmxFunctionAndMethodMap.has(fullyQualifiedFilename)){
|
|
316
|
+
concElement = _.cloneDeep(el);
|
|
317
|
+
concElement.setFullyQualifiedName(fullyQualifiedFilename);
|
|
318
|
+
concElement.clearGenericParameters();
|
|
319
|
+
concreteArguments.map((param) => {
|
|
320
|
+
const parameter = this.createOrGetFamixConcreteType(param);
|
|
321
|
+
concElement.addConcreteParameter(parameter);
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
if (el instanceof Famix.ParametricClass) {
|
|
325
|
+
this.fmxClassMap.set(fullyQualifiedFilename, concElement as Famix.ParametricClass);
|
|
326
|
+
} else if (el instanceof Famix.ParametricInterface) {
|
|
327
|
+
this.fmxInterfaceMap.set(fullyQualifiedFilename, concElement as Famix.ParametricInterface);
|
|
328
|
+
} else if (el instanceof Famix.ParametricFunction) {
|
|
329
|
+
this.fmxFunctionAndMethodMap.set(fullyQualifiedFilename, concElement as Famix.ParametricFunction);
|
|
330
|
+
} else if (el instanceof Famix.ParametricMethod) {
|
|
331
|
+
this.fmxFunctionAndMethodMap.set(fullyQualifiedFilename, concElement as Famix.ParametricMethod);
|
|
332
|
+
}
|
|
333
|
+
this.famixRep.addElement(concElement);
|
|
334
|
+
this.fmxElementObjectMap.set(concElement,elDeclaration);
|
|
335
|
+
} else {
|
|
336
|
+
if (el instanceof Famix.ParametricClass) {
|
|
337
|
+
concElement = this.fmxClassMap.get(fullyQualifiedFilename);
|
|
338
|
+
} else if (el instanceof Famix.ParametricInterface) {
|
|
339
|
+
concElement = this.fmxInterfaceMap.get(fullyQualifiedFilename);
|
|
340
|
+
} else if (el instanceof Famix.ParametricFunction) {
|
|
341
|
+
concElement = this.fmxFunctionAndMethodMap.get(fullyQualifiedFilename);
|
|
342
|
+
} else if (el instanceof Famix.ParametricMethod) {
|
|
343
|
+
concElement = this.fmxFunctionAndMethodMap.get(fullyQualifiedFilename);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return concElement;
|
|
347
|
+
}
|
|
348
|
+
|
|
285
349
|
/**
|
|
286
350
|
* Creates a Famix property
|
|
287
351
|
* @param property A property
|
|
@@ -302,22 +366,39 @@ export class EntityDictionary {
|
|
|
302
366
|
const fmxType = this.createOrGetFamixType(propTypeName, property);
|
|
303
367
|
fmxProperty.setDeclaredType(fmxType);
|
|
304
368
|
|
|
305
|
-
|
|
369
|
+
// add the visibility (public, private, etc.) to the fmxProperty
|
|
370
|
+
fmxProperty.visibility = "";
|
|
371
|
+
|
|
372
|
+
property.getModifiers().forEach(m => {
|
|
373
|
+
switch (m.getText()) {
|
|
374
|
+
case Scope.Public:
|
|
375
|
+
fmxProperty.visibility = "public";
|
|
376
|
+
break;
|
|
377
|
+
case Scope.Protected:
|
|
378
|
+
fmxProperty.visibility = "protected";
|
|
379
|
+
break;
|
|
380
|
+
case Scope.Private:
|
|
381
|
+
fmxProperty.visibility = "private";
|
|
382
|
+
break;
|
|
383
|
+
case "static":
|
|
384
|
+
fmxProperty.setIsClassSide(true);
|
|
385
|
+
break;
|
|
386
|
+
case "readonly":
|
|
387
|
+
fmxProperty.readOnly = true;
|
|
388
|
+
break;
|
|
389
|
+
default:
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
|
|
306
394
|
if (!isSignature && property.getExclamationTokenNode()) {
|
|
307
|
-
fmxProperty.
|
|
395
|
+
fmxProperty.isDefinitelyAssigned = true;
|
|
308
396
|
}
|
|
309
397
|
if (property.getQuestionTokenNode()) {
|
|
310
|
-
fmxProperty.
|
|
398
|
+
fmxProperty.isOptional = true;
|
|
311
399
|
}
|
|
312
400
|
if (property.getName().substring(0, 1) === "#") {
|
|
313
|
-
fmxProperty.
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (fmxProperty.getModifiers().has("static")) {
|
|
317
|
-
fmxProperty.setIsClassSide(true);
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
fmxProperty.setIsClassSide(false);
|
|
401
|
+
fmxProperty.isJavaScriptPrivate = true;
|
|
321
402
|
}
|
|
322
403
|
|
|
323
404
|
this.makeFamixIndexFileAnchor(property, fmxProperty);
|
|
@@ -335,89 +416,102 @@ export class EntityDictionary {
|
|
|
335
416
|
* @param currentCC The cyclomatic complexity metrics of the current source file
|
|
336
417
|
* @returns The Famix model of the method or the accessor
|
|
337
418
|
*/
|
|
338
|
-
public
|
|
339
|
-
let fmxMethod: Famix.Method | Famix.Accessor;
|
|
340
|
-
if (method instanceof GetAccessorDeclaration || method instanceof SetAccessorDeclaration) {
|
|
341
|
-
fmxMethod = new Famix.Accessor();
|
|
342
|
-
const isGetter = method instanceof GetAccessorDeclaration;
|
|
343
|
-
const isSetter = method instanceof SetAccessorDeclaration;
|
|
344
|
-
if (isGetter) {(fmxMethod as Famix.Accessor).setKind("getter");}
|
|
345
|
-
if (isSetter) {(fmxMethod as Famix.Accessor).setKind("setter");}
|
|
346
|
-
this.famixRep.addElement(fmxMethod);
|
|
347
|
-
}
|
|
348
|
-
else {
|
|
349
|
-
fmxMethod = new Famix.Method();
|
|
350
|
-
this.famixRep.addElement(fmxMethod);
|
|
351
|
-
}
|
|
352
|
-
const isConstructor = method instanceof ConstructorDeclaration;
|
|
353
|
-
const isSignature = method instanceof MethodSignature;
|
|
419
|
+
public createOrGetFamixMethod(method: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration, currentCC: unknown): Famix.Method | Famix.Accessor | Famix.ParametricMethod {
|
|
420
|
+
let fmxMethod: Famix.Method | Famix.Accessor | Famix.ParametricMethod;
|
|
354
421
|
const isGeneric = method.getTypeParameters().length > 0;
|
|
355
|
-
|
|
422
|
+
const functionFullyQualifiedName = FQNFunctions.getFQN(method);
|
|
423
|
+
if (!this.fmxFunctionAndMethodMap.has(functionFullyQualifiedName)) {
|
|
424
|
+
|
|
425
|
+
if (method instanceof GetAccessorDeclaration || method instanceof SetAccessorDeclaration) {
|
|
426
|
+
fmxMethod = new Famix.Accessor();
|
|
427
|
+
const isGetter = method instanceof GetAccessorDeclaration;
|
|
428
|
+
const isSetter = method instanceof SetAccessorDeclaration;
|
|
429
|
+
if (isGetter) {(fmxMethod as Famix.Accessor).setKind("getter");}
|
|
430
|
+
if (isSetter) {(fmxMethod as Famix.Accessor).setKind("setter");}
|
|
431
|
+
this.famixRep.addElement(fmxMethod);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
if (isGeneric) {
|
|
435
|
+
fmxMethod = new Famix.ParametricMethod();
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
fmxMethod = new Famix.Method();
|
|
439
|
+
}
|
|
440
|
+
this.famixRep.addElement(fmxMethod);
|
|
441
|
+
}
|
|
442
|
+
const isConstructor = method instanceof ConstructorDeclaration;
|
|
443
|
+
const isSignature = method instanceof MethodSignature;
|
|
444
|
+
|
|
445
|
+
let isAbstract = false;
|
|
446
|
+
let isStatic = false;
|
|
447
|
+
if (method instanceof MethodDeclaration || method instanceof GetAccessorDeclaration || method instanceof SetAccessorDeclaration) {
|
|
448
|
+
isAbstract = method.isAbstract();
|
|
449
|
+
isStatic = method.isStatic();
|
|
450
|
+
}
|
|
356
451
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
452
|
+
if (isConstructor) {(fmxMethod as Famix.Accessor).setKind("constructor");}
|
|
453
|
+
fmxMethod.setIsAbstract(isAbstract);
|
|
454
|
+
fmxMethod.setIsClassSide(isStatic);
|
|
455
|
+
fmxMethod.setIsPrivate((method instanceof MethodDeclaration || method instanceof GetAccessorDeclaration || method instanceof SetAccessorDeclaration) ? (method.getModifiers().find(x => x.getText() === 'private')) !== undefined : false);
|
|
456
|
+
fmxMethod.setIsProtected((method instanceof MethodDeclaration || method instanceof GetAccessorDeclaration || method instanceof SetAccessorDeclaration) ? (method.getModifiers().find(x => x.getText() === 'protected')) !== undefined : false);
|
|
457
|
+
fmxMethod.setSignature(Helpers.computeSignature(method.getText()));
|
|
363
458
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
459
|
+
let methodName: string;
|
|
460
|
+
if (isConstructor) {
|
|
461
|
+
methodName = "constructor";
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
methodName = (method as MethodDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration).getName();
|
|
465
|
+
}
|
|
466
|
+
fmxMethod.setName(methodName);
|
|
370
467
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
methodName = (method as MethodDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration).getName();
|
|
377
|
-
}
|
|
378
|
-
fmxMethod.setName(methodName);
|
|
468
|
+
if (!isConstructor) {
|
|
469
|
+
if (method.getName().substring(0, 1) === "#") {
|
|
470
|
+
fmxMethod.setIsPrivate(true);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
379
473
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
474
|
+
if (!fmxMethod.getIsPrivate() && !fmxMethod.getIsProtected()) {
|
|
475
|
+
fmxMethod.setIsPublic(true);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
fmxMethod.setIsPublic(false);
|
|
383
479
|
}
|
|
384
|
-
}
|
|
385
480
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
481
|
+
if (!isSignature) {
|
|
482
|
+
fmxMethod.setCyclomaticComplexity(currentCC[fmxMethod.getName()]);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
fmxMethod.setCyclomaticComplexity(0);
|
|
486
|
+
}
|
|
392
487
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
488
|
+
let methodTypeName = this.UNKNOWN_VALUE;
|
|
489
|
+
try {
|
|
490
|
+
methodTypeName = method.getReturnType().getText().trim();
|
|
491
|
+
} catch (error) {
|
|
492
|
+
logger.error(`> WARNING: got exception ${error}. Failed to get usable name for return type of method: ${fmxMethod.getName()}. Continuing...`);
|
|
493
|
+
}
|
|
399
494
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
495
|
+
const fmxType = this.createOrGetFamixType(methodTypeName, method);
|
|
496
|
+
fmxMethod.setDeclaredType(fmxType);
|
|
497
|
+
fmxMethod.setNumberOfLinesOfCode(method.getEndLineNumber() - method.getStartLineNumber());
|
|
498
|
+
const parameters = method.getParameters();
|
|
499
|
+
fmxMethod.setNumberOfParameters(parameters.length);
|
|
406
500
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
501
|
+
if (!isSignature) {
|
|
502
|
+
fmxMethod.setNumberOfStatements(method.getStatements().length);
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
fmxMethod.setNumberOfStatements(0);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
this.makeFamixIndexFileAnchor(method, fmxMethod);
|
|
412
509
|
|
|
413
|
-
|
|
414
|
-
fmxMethod.setNumberOfStatements(method.getStatements().length);
|
|
510
|
+
this.fmxFunctionAndMethodMap.set(functionFullyQualifiedName, fmxMethod);
|
|
415
511
|
}
|
|
416
512
|
else {
|
|
417
|
-
fmxMethod.
|
|
513
|
+
fmxMethod = this.fmxFunctionAndMethodMap.get(functionFullyQualifiedName) as (Famix.Method | Famix.Accessor | Famix.ParametricMethod);
|
|
418
514
|
}
|
|
419
|
-
|
|
420
|
-
this.makeFamixIndexFileAnchor(method, fmxMethod);
|
|
421
515
|
|
|
422
516
|
this.fmxElementObjectMap.set(fmxMethod,method);
|
|
423
517
|
|
|
@@ -430,38 +524,54 @@ export class EntityDictionary {
|
|
|
430
524
|
* @param currentCC The cyclomatic complexity metrics of the current source file
|
|
431
525
|
* @returns The Famix model of the function
|
|
432
526
|
*/
|
|
433
|
-
public
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
527
|
+
public createOrGetFamixFunction(func: FunctionDeclaration | FunctionExpression, currentCC: unknown): Famix.Function | Famix.ParametricFunction {
|
|
528
|
+
let fmxFunction: Famix.Function | Famix.ParametricFunction;
|
|
529
|
+
const isGeneric = func.getTypeParameters().length > 0;
|
|
530
|
+
const functionFullyQualifiedName = FQNFunctions.getFQN(func);
|
|
531
|
+
if (!this.fmxFunctionAndMethodMap.has(functionFullyQualifiedName)) {
|
|
532
|
+
if (isGeneric) {
|
|
533
|
+
fmxFunction = new Famix.ParametricFunction();
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
fmxFunction = new Famix.Function();
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (func.getName()) {
|
|
540
|
+
fmxFunction.setName(func.getName());
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
fmxFunction.setName("anonymous");
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
fmxFunction.setSignature(Helpers.computeSignature(func.getText()));
|
|
547
|
+
fmxFunction.setCyclomaticComplexity(currentCC[fmxFunction.getName()]);
|
|
548
|
+
fmxFunction.setFullyQualifiedName(functionFullyQualifiedName);
|
|
549
|
+
|
|
550
|
+
let functionTypeName = this.UNKNOWN_VALUE;
|
|
551
|
+
try {
|
|
552
|
+
functionTypeName = func.getReturnType().getText().trim();
|
|
553
|
+
} catch (error) {
|
|
554
|
+
logger.error(`> WARNING: got exception ${error}. Failed to get usable name for return type of function: ${func.getName()}. Continuing...`);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const fmxType = this.createOrGetFamixType(functionTypeName, func);
|
|
558
|
+
fmxFunction.setDeclaredType(fmxType);
|
|
559
|
+
fmxFunction.setNumberOfLinesOfCode(func.getEndLineNumber() - func.getStartLineNumber());
|
|
560
|
+
const parameters = func.getParameters();
|
|
561
|
+
fmxFunction.setNumberOfParameters(parameters.length);
|
|
562
|
+
fmxFunction.setNumberOfStatements(func.getStatements().length);
|
|
563
|
+
|
|
564
|
+
this.makeFamixIndexFileAnchor(func, fmxFunction);
|
|
565
|
+
|
|
566
|
+
this.famixRep.addElement(fmxFunction);
|
|
567
|
+
|
|
568
|
+
this.fmxElementObjectMap.set(fmxFunction,func);
|
|
569
|
+
|
|
570
|
+
this.fmxFunctionAndMethodMap.set(functionFullyQualifiedName, fmxFunction);
|
|
437
571
|
}
|
|
438
572
|
else {
|
|
439
|
-
fmxFunction.
|
|
573
|
+
fmxFunction = this.fmxFunctionAndMethodMap.get(functionFullyQualifiedName) as (Famix.Function | Famix.ParametricFunction);
|
|
440
574
|
}
|
|
441
|
-
fmxFunction.setSignature(Helpers.computeSignature(func.getText()));
|
|
442
|
-
fmxFunction.setCyclomaticComplexity(currentCC[fmxFunction.getName()]);
|
|
443
|
-
const isGeneric = func.getTypeParameters().length > 0;
|
|
444
|
-
fmxFunction.setIsGeneric(isGeneric);
|
|
445
|
-
|
|
446
|
-
let functionTypeName = this.UNKNOWN_VALUE;
|
|
447
|
-
try {
|
|
448
|
-
functionTypeName = func.getReturnType().getText().trim();
|
|
449
|
-
} catch (error) {
|
|
450
|
-
logger.error(`> WARNING: got exception ${error}. Failed to get usable name for return type of function: ${func.getName()}. Continuing...`);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const fmxType = this.createOrGetFamixType(functionTypeName, func);
|
|
454
|
-
fmxFunction.setDeclaredType(fmxType);
|
|
455
|
-
fmxFunction.setNumberOfLinesOfCode(func.getEndLineNumber() - func.getStartLineNumber());
|
|
456
|
-
const parameters = func.getParameters();
|
|
457
|
-
fmxFunction.setNumberOfParameters(parameters.length);
|
|
458
|
-
fmxFunction.setNumberOfStatements(func.getStatements().length);
|
|
459
|
-
|
|
460
|
-
this.makeFamixIndexFileAnchor(func, fmxFunction);
|
|
461
|
-
|
|
462
|
-
this.famixRep.addElement(fmxFunction);
|
|
463
|
-
|
|
464
|
-
this.fmxElementObjectMap.set(fmxFunction,func);
|
|
465
575
|
|
|
466
576
|
return fmxFunction;
|
|
467
577
|
}
|
|
@@ -500,8 +610,10 @@ export class EntityDictionary {
|
|
|
500
610
|
* @returns The Famix model of the type parameter
|
|
501
611
|
*/
|
|
502
612
|
public createFamixParameterType(tp: TypeParameterDeclaration): Famix.ParameterType {
|
|
613
|
+
|
|
503
614
|
const fmxParameterType = new Famix.ParameterType();
|
|
504
|
-
|
|
615
|
+
|
|
616
|
+
fmxParameterType.setName(tp.getName());
|
|
505
617
|
|
|
506
618
|
this.makeFamixIndexFileAnchor(tp, fmxParameterType);
|
|
507
619
|
|
|
@@ -512,6 +624,71 @@ export class EntityDictionary {
|
|
|
512
624
|
return fmxParameterType;
|
|
513
625
|
}
|
|
514
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Creates a Famix type parameter
|
|
629
|
+
* @param tp A type parameter
|
|
630
|
+
* @returns The Famix model of the type parameter
|
|
631
|
+
*/
|
|
632
|
+
public createOrGetFamixConcreteType(param: TypeNode): Famix.ParameterType | Famix.PrimitiveType | Famix.Class | Famix.Interface {
|
|
633
|
+
const typeParameterDeclaration = param.getSymbol()?.getDeclarations()[0] as TypeParameterDeclaration;
|
|
634
|
+
const parameterTypeName : string = param.getText();
|
|
635
|
+
let fmxParameterType: Famix.Type | Famix.Class | Famix.Interface;
|
|
636
|
+
|
|
637
|
+
let isClassOrInterface = false;
|
|
638
|
+
if (this.fmxClassMap.has(parameterTypeName)){
|
|
639
|
+
this.fmxClassMap.forEach((obj, name) => {
|
|
640
|
+
if(obj instanceof Famix.ParametricClass){
|
|
641
|
+
if (name === param.getText() && obj.getGenericParameters().size>0) {
|
|
642
|
+
fmxParameterType = obj;
|
|
643
|
+
isClassOrInterface = true;
|
|
644
|
+
}
|
|
645
|
+
} else {
|
|
646
|
+
if (name === param.getText()) {
|
|
647
|
+
fmxParameterType = obj;
|
|
648
|
+
isClassOrInterface = true;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (this.fmxInterfaceMap.has(parameterTypeName)){
|
|
655
|
+
this.fmxInterfaceMap.forEach((obj, name) => {
|
|
656
|
+
if(obj instanceof Famix.ParametricInterface){
|
|
657
|
+
if (name === param.getText() && obj.getGenericParameters().size>0) {
|
|
658
|
+
fmxParameterType = obj;
|
|
659
|
+
isClassOrInterface = true;
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
if (name === param.getText()) {
|
|
663
|
+
fmxParameterType = obj;
|
|
664
|
+
isClassOrInterface = true;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
})
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if(!isClassOrInterface){
|
|
671
|
+
if (!this.fmxTypeMap.has(parameterTypeName)) {
|
|
672
|
+
if (parameterTypeName === "number" || parameterTypeName === "string" || parameterTypeName === "boolean" || parameterTypeName === "bigint" || parameterTypeName === "symbol" || parameterTypeName === "undefined" || parameterTypeName === "null" || parameterTypeName === "any" || parameterTypeName === "unknown" || parameterTypeName === "never" || parameterTypeName === "void") {
|
|
673
|
+
fmxParameterType = new Famix.PrimitiveType();
|
|
674
|
+
fmxParameterType.setIsStub(true);
|
|
675
|
+
} else {
|
|
676
|
+
fmxParameterType = new Famix.ParameterType();
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
fmxParameterType.setName(parameterTypeName);
|
|
680
|
+
this.famixRep.addElement(fmxParameterType);
|
|
681
|
+
this.fmxTypeMap.set(parameterTypeName, fmxParameterType);
|
|
682
|
+
this.fmxElementObjectMap.set(fmxParameterType,typeParameterDeclaration);
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
fmxParameterType = this.fmxTypeMap.get(parameterTypeName);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return fmxParameterType;
|
|
690
|
+
}
|
|
691
|
+
|
|
515
692
|
/**
|
|
516
693
|
* Creates a Famix variable
|
|
517
694
|
* @param variable A variable
|
|
@@ -519,24 +696,24 @@ export class EntityDictionary {
|
|
|
519
696
|
*/
|
|
520
697
|
public createFamixVariable(variable: VariableDeclaration): Famix.Variable {
|
|
521
698
|
const fmxVariable = new Famix.Variable();
|
|
522
|
-
|
|
699
|
+
|
|
523
700
|
let variableTypeName = this.UNKNOWN_VALUE;
|
|
524
701
|
try {
|
|
525
702
|
variableTypeName = variable.getType().getText().trim();
|
|
526
703
|
} catch (error) {
|
|
527
704
|
logger.error(`> WARNING: got exception ${error}. Failed to get usable name for variable: ${variable.getName()}. Continuing...`);
|
|
528
705
|
}
|
|
529
|
-
|
|
706
|
+
|
|
530
707
|
const fmxType = this.createOrGetFamixType(variableTypeName, variable);
|
|
531
708
|
fmxVariable.setDeclaredType(fmxType);
|
|
532
709
|
fmxVariable.setName(variable.getName());
|
|
533
|
-
|
|
710
|
+
|
|
534
711
|
this.makeFamixIndexFileAnchor(variable, fmxVariable);
|
|
535
|
-
|
|
712
|
+
|
|
536
713
|
this.famixRep.addElement(fmxVariable);
|
|
537
|
-
|
|
714
|
+
|
|
538
715
|
this.fmxElementObjectMap.set(fmxVariable,variable);
|
|
539
|
-
|
|
716
|
+
|
|
540
717
|
return fmxVariable;
|
|
541
718
|
}
|
|
542
719
|
|
|
@@ -640,19 +817,23 @@ export class EntityDictionary {
|
|
|
640
817
|
* @param element A ts-morph element
|
|
641
818
|
* @returns The Famix model of the type
|
|
642
819
|
*/
|
|
643
|
-
public createOrGetFamixType(typeName: string, element:
|
|
644
|
-
let fmxType: Famix.Type | Famix.PrimitiveType | Famix.
|
|
820
|
+
public createOrGetFamixType(typeName: string, element: TypeDeclaration): Famix.Type | Famix.PrimitiveType | Famix.ParameterType {
|
|
821
|
+
let fmxType: Famix.Type | Famix.PrimitiveType | Famix.ParameterType;
|
|
645
822
|
let isPrimitiveType = false;
|
|
646
|
-
let
|
|
823
|
+
let isParameterType = false;
|
|
647
824
|
|
|
648
825
|
logger.debug("Creating (or getting) type: '" + typeName + "' of element: " + element?.getText() + " of kind: " + element?.getKindName());
|
|
649
826
|
let ancestor: Famix.ContainerEntity;
|
|
650
827
|
if (element !== undefined) {
|
|
651
828
|
const typeAncestor = Helpers.findTypeAncestor(element);
|
|
829
|
+
if (!typeAncestor) {
|
|
830
|
+
throw new Error(`Ancestor not found for element ${element.getText()}.`);
|
|
831
|
+
}
|
|
652
832
|
const ancestorFullyQualifiedName = FQNFunctions.getFQN(typeAncestor);
|
|
653
833
|
ancestor = this.famixRep.getFamixEntityByFullyQualifiedName(ancestorFullyQualifiedName) as Famix.ContainerEntity;
|
|
654
834
|
if (!ancestor) {
|
|
655
|
-
|
|
835
|
+
logger.debug(`Ancestor ${FQNFunctions.getFQN(typeAncestor)} not found. Adding the new type.`);
|
|
836
|
+
ancestor = this.createOrGetFamixType(typeAncestor.getText(), typeAncestor as TypeDeclaration);
|
|
656
837
|
}
|
|
657
838
|
}
|
|
658
839
|
|
|
@@ -661,7 +842,7 @@ export class EntityDictionary {
|
|
|
661
842
|
}
|
|
662
843
|
|
|
663
844
|
if(!isPrimitiveType && typeName.includes("<") && typeName.includes(">") && !(typeName.includes("=>"))) {
|
|
664
|
-
|
|
845
|
+
isParameterType = true;
|
|
665
846
|
}
|
|
666
847
|
|
|
667
848
|
if (!this.fmxTypeMap.has(typeName)) {
|
|
@@ -669,16 +850,16 @@ export class EntityDictionary {
|
|
|
669
850
|
fmxType = new Famix.PrimitiveType();
|
|
670
851
|
fmxType.setIsStub(true);
|
|
671
852
|
}
|
|
672
|
-
else if (
|
|
673
|
-
fmxType = new Famix.
|
|
853
|
+
else if (isParameterType) {
|
|
854
|
+
fmxType = new Famix.ParameterType();
|
|
674
855
|
const parameterTypeNames = typeName.substring(typeName.indexOf("<") + 1, typeName.indexOf(">")).split(",").map(s => s.trim());
|
|
675
856
|
const baseTypeName = typeName.substring(0, typeName.indexOf("<")).trim();
|
|
676
857
|
parameterTypeNames.forEach(parameterTypeName => {
|
|
677
858
|
const fmxParameterType = this.createOrGetFamixType(parameterTypeName, element);
|
|
678
|
-
(fmxType as Famix.
|
|
859
|
+
(fmxType as Famix.ParameterType).addArgument(fmxParameterType);
|
|
679
860
|
});
|
|
680
861
|
const fmxBaseType = this.createOrGetFamixType(baseTypeName, element);
|
|
681
|
-
(fmxType as Famix.
|
|
862
|
+
(fmxType as Famix.ParameterType).setBaseType(fmxBaseType);
|
|
682
863
|
}
|
|
683
864
|
else {
|
|
684
865
|
fmxType = new Famix.Type();
|
|
@@ -709,16 +890,24 @@ export class EntityDictionary {
|
|
|
709
890
|
*/
|
|
710
891
|
public createFamixAccess(node: Identifier, id: number): void {
|
|
711
892
|
const fmxVar = this.famixRep.getFamixEntityById(id) as Famix.StructuralEntity;
|
|
893
|
+
if (!fmxVar) {
|
|
894
|
+
throw new Error(`Famix entity with id ${id} not found, for node ${node.getText()} in ${node.getSourceFile().getBaseName()} at line ${node.getStartLineNumber()}.`);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
logger.debug(`Creating FamixAccess. Node: [${node.getKindName()}] '${node.getText()}' at line ${node.getStartLineNumber()} in ${node.getSourceFile().getBaseName()}, id: ${id} refers to fmxVar '${fmxVar.getFullyQualifiedName()}'.`);
|
|
898
|
+
|
|
712
899
|
const nodeReferenceAncestor = Helpers.findAncestor(node);
|
|
713
900
|
const ancestorFullyQualifiedName = FQNFunctions.getFQN(nodeReferenceAncestor);
|
|
714
|
-
|
|
901
|
+
let accessor = this.famixRep.getFamixEntityByFullyQualifiedName(ancestorFullyQualifiedName) as Famix.ContainerEntity;
|
|
902
|
+
if (!accessor) {
|
|
903
|
+
logger.error(`Ancestor ${ancestorFullyQualifiedName} of kind ${nodeReferenceAncestor.getKindName()} not found.`);
|
|
904
|
+
// accessor = this.createOrGetFamixType(ancestorFullyQualifiedName, nodeReferenceAncestor as TypeDeclaration);
|
|
905
|
+
}
|
|
715
906
|
|
|
716
907
|
const fmxAccess = new Famix.Access();
|
|
717
908
|
fmxAccess.setAccessor(accessor);
|
|
718
909
|
fmxAccess.setVariable(fmxVar);
|
|
719
910
|
|
|
720
|
-
this.makeFamixIndexFileAnchor(node, fmxAccess);
|
|
721
|
-
|
|
722
911
|
this.famixRep.addElement(fmxAccess);
|
|
723
912
|
|
|
724
913
|
this.fmxElementObjectMap.set(fmxAccess,node);
|
|
@@ -744,8 +933,6 @@ export class EntityDictionary {
|
|
|
744
933
|
fmxInvocation.addCandidate(fmxMethodOrFunction);
|
|
745
934
|
fmxInvocation.setSignature(fmxMethodOrFunction.getSignature());
|
|
746
935
|
|
|
747
|
-
this.makeFamixIndexFileAnchor(node, fmxInvocation);
|
|
748
|
-
|
|
749
936
|
this.famixRep.addElement(fmxInvocation);
|
|
750
937
|
|
|
751
938
|
this.fmxElementObjectMap.set(fmxInvocation,node);
|
|
@@ -813,14 +1000,20 @@ export class EntityDictionary {
|
|
|
813
1000
|
fmxInheritance.setSubclass(subClass);
|
|
814
1001
|
fmxInheritance.setSuperclass(superClass);
|
|
815
1002
|
|
|
816
|
-
this.makeFamixIndexFileAnchor(null, fmxInheritance);
|
|
817
|
-
|
|
818
1003
|
this.famixRep.addElement(fmxInheritance);
|
|
819
1004
|
|
|
820
1005
|
this.fmxElementObjectMap.set(fmxInheritance,null);
|
|
821
1006
|
|
|
822
1007
|
}
|
|
823
1008
|
|
|
1009
|
+
public createFamixImportClause(importedEntity: Famix.NamedEntity, importingEntity: Famix.Module) {
|
|
1010
|
+
const fmxImportClause = new Famix.ImportClause();
|
|
1011
|
+
fmxImportClause.setImportedEntity(importedEntity);
|
|
1012
|
+
fmxImportClause.setImportingEntity(importingEntity);
|
|
1013
|
+
importingEntity.addOutgoingImport(fmxImportClause);
|
|
1014
|
+
this.famixRep.addElement(fmxImportClause);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
824
1017
|
/**
|
|
825
1018
|
* Creates a Famix import clause
|
|
826
1019
|
* @param importClauseInfo The information needed to create a Famix import clause
|
|
@@ -831,8 +1024,8 @@ export class EntityDictionary {
|
|
|
831
1024
|
* @param isInExports A boolean indicating if the imported entity is in the exports
|
|
832
1025
|
* @param isDefaultExport A boolean indicating if the imported entity is a default export
|
|
833
1026
|
*/
|
|
834
|
-
public
|
|
835
|
-
const {importDeclaration, importer, moduleSpecifierFilePath, importElement, isInExports, isDefaultExport} = importClauseInfo;
|
|
1027
|
+
public oldCreateFamixImportClause(importClauseInfo: {importDeclaration?: ImportDeclaration | ImportEqualsDeclaration, importerSourceFile: SourceFile, moduleSpecifierFilePath: string, importElement: ImportSpecifier | Identifier, isInExports: boolean, isDefaultExport: boolean}): void {
|
|
1028
|
+
const {importDeclaration, importerSourceFile: importer, moduleSpecifierFilePath, importElement, isInExports, isDefaultExport} = importClauseInfo;
|
|
836
1029
|
logger.debug(`createFamixImportClause: Creating import clause:`);
|
|
837
1030
|
const fmxImportClause = new Famix.ImportClause();
|
|
838
1031
|
|
|
@@ -844,10 +1037,12 @@ export class EntityDictionary {
|
|
|
844
1037
|
const absolutePath = path.normalize(moduleSpecifierFilePath);
|
|
845
1038
|
// convert the path and remove any windows backslashes introduced by path.normalize
|
|
846
1039
|
const pathInProject: string = this.convertToRelativePath(absolutePath, absolutePathProject).replace(/\\/g, "/");
|
|
847
|
-
|
|
848
1040
|
let pathName = "{" + pathInProject + "}.";
|
|
849
1041
|
|
|
850
1042
|
// Named imports, e.g. import { ClassW } from "./complexExportModule";
|
|
1043
|
+
|
|
1044
|
+
// Start with simple import clause (without referring to the actual variable)
|
|
1045
|
+
|
|
851
1046
|
if (importDeclaration instanceof ImportDeclaration
|
|
852
1047
|
&& importElement instanceof ImportSpecifier) {
|
|
853
1048
|
importedEntityName = importElement.getName();
|
|
@@ -863,6 +1058,8 @@ export class EntityDictionary {
|
|
|
863
1058
|
}
|
|
864
1059
|
this.makeFamixIndexFileAnchor(importElement, importedEntity);
|
|
865
1060
|
importedEntity.setFullyQualifiedName(pathName);
|
|
1061
|
+
// must add entity to repository
|
|
1062
|
+
this.famixRep.addElement(importedEntity);
|
|
866
1063
|
}
|
|
867
1064
|
}
|
|
868
1065
|
// handle import equals declarations, e.g. import myModule = require("./complexExportModule");
|
|
@@ -884,8 +1081,8 @@ export class EntityDictionary {
|
|
|
884
1081
|
this.makeFamixIndexFileAnchor(importElement, importedEntity);
|
|
885
1082
|
importedEntity.setFullyQualifiedName(pathName);
|
|
886
1083
|
}
|
|
887
|
-
|
|
888
|
-
this.famixRep.addElement(importedEntity);
|
|
1084
|
+
// I don't think it should be added to the repository if it exists already
|
|
1085
|
+
if (!isInExports) this.famixRep.addElement(importedEntity);
|
|
889
1086
|
const importerFullyQualifiedName = FQNFunctions.getFQN(importer);
|
|
890
1087
|
const fmxImporter = this.famixRep.getFamixEntityByFullyQualifiedName(importerFullyQualifiedName) as Famix.Module;
|
|
891
1088
|
fmxImportClause.setImportingEntity(fmxImporter);
|
|
@@ -899,9 +1096,6 @@ export class EntityDictionary {
|
|
|
899
1096
|
logger.debug(`createFamixImportClause: ${fmxImportClause.getImportedEntity()?.getName()} (of type ${
|
|
900
1097
|
Helpers.getSubTypeName(fmxImportClause.getImportedEntity())}) is imported by ${fmxImportClause.getImportingEntity()?.getName()}`);
|
|
901
1098
|
|
|
902
|
-
// make an index file anchor for the import clause
|
|
903
|
-
this.makeFamixIndexFileAnchor(importDeclaration, fmxImportClause);
|
|
904
|
-
|
|
905
1099
|
fmxImporter.addOutgoingImport(fmxImportClause);
|
|
906
1100
|
|
|
907
1101
|
this.famixRep.addElement(fmxImportClause);
|
|
@@ -909,7 +1103,362 @@ export class EntityDictionary {
|
|
|
909
1103
|
this.fmxElementObjectMap.set(fmxImportClause,importDeclaration);
|
|
910
1104
|
}
|
|
911
1105
|
|
|
1106
|
+
/**
|
|
1107
|
+
* Creates a Famix Arrow Function
|
|
1108
|
+
* @param arrowExpression An Expression
|
|
1109
|
+
* @returns The Famix model of the variable
|
|
1110
|
+
*/
|
|
1111
|
+
public createFamixArrowFunction(arrowExpression: Expression ,currentCC: unknown): Famix.ArrowFunction | Famix.ParametricArrowFunction {
|
|
1112
|
+
|
|
1113
|
+
let fmxArrowFunction: Famix.ArrowFunction | Famix.ParametricArrowFunction;
|
|
1114
|
+
|
|
1115
|
+
const arrowFunction = arrowExpression.asKindOrThrow(SyntaxKind.ArrowFunction);
|
|
1116
|
+
|
|
1117
|
+
const isGeneric = arrowFunction.getTypeParameters().length > 0;
|
|
1118
|
+
|
|
1119
|
+
if (isGeneric) {
|
|
1120
|
+
fmxArrowFunction = new Famix.ParametricArrowFunction();
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
fmxArrowFunction = new Famix.ArrowFunction();
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Get the parent of the arrow function (the variable declaration)
|
|
1127
|
+
const parent = arrowFunction.getParentIfKind(SyntaxKind.VariableDeclaration);
|
|
1128
|
+
let functionName = '(NO_NAME)';
|
|
1129
|
+
|
|
1130
|
+
if (parent && parent instanceof VariableDeclaration) {
|
|
1131
|
+
// Get the name of the variable
|
|
1132
|
+
functionName = parent.getName();
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
if (functionName) {
|
|
1136
|
+
fmxArrowFunction.setName(functionName);
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
fmxArrowFunction.setName("anonymous");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Signature of an arrow function is (parameters) => return_type
|
|
1143
|
+
const parametersSignature = arrowFunction.getParameters().map(p => p.getText()).join(", ");
|
|
1144
|
+
const returnTypeSignature = arrowFunction.getReturnType().getText();
|
|
1145
|
+
fmxArrowFunction.setSignature(`(${parametersSignature}) => ${returnTypeSignature}`);
|
|
1146
|
+
fmxArrowFunction.setCyclomaticComplexity(currentCC[fmxArrowFunction.getName()]);
|
|
1147
|
+
|
|
1148
|
+
let functionTypeName = this.UNKNOWN_VALUE;
|
|
1149
|
+
try {
|
|
1150
|
+
functionTypeName = arrowFunction.getReturnType().getText().trim();
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
logger.error(`> WARNING: got exception ${error}. Failed to get usable name for return type of function: ${functionName}. Continuing...`);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const fmxType = this.createOrGetFamixType(functionTypeName, arrowFunction as unknown as FunctionDeclaration);
|
|
1156
|
+
fmxArrowFunction.setDeclaredType(fmxType);
|
|
1157
|
+
fmxArrowFunction.setNumberOfLinesOfCode(arrowFunction.getEndLineNumber() - arrowFunction.getStartLineNumber());
|
|
1158
|
+
const parameters = arrowFunction.getParameters();
|
|
1159
|
+
fmxArrowFunction.setNumberOfParameters(parameters.length);
|
|
1160
|
+
fmxArrowFunction.setNumberOfStatements(arrowFunction.getStatements().length);
|
|
1161
|
+
|
|
1162
|
+
this.makeFamixIndexFileAnchor(arrowExpression as unknown as TSMorphObjectType, fmxArrowFunction);
|
|
1163
|
+
this.famixRep.addElement(fmxArrowFunction);
|
|
1164
|
+
this.fmxElementObjectMap.set(fmxArrowFunction,arrowFunction as unknown as TSMorphObjectType);
|
|
1165
|
+
|
|
1166
|
+
return fmxArrowFunction;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* Creates a Famix concretisation
|
|
1171
|
+
* @param cls A class
|
|
1172
|
+
* @returns The Famix model of the concretisation
|
|
1173
|
+
*/
|
|
1174
|
+
public createFamixConcretisation(conEntity : Famix.ParametricClass | Famix.ParametricInterface | Famix.ParametricFunction | Famix.ParametricMethod ,genEntity : Famix.ParametricClass | Famix.ParametricInterface | Famix.ParametricFunction | Famix.ParametricMethod): Famix.Concretisation {
|
|
1175
|
+
|
|
1176
|
+
const fmxConcretisation : Famix.Concretisation = new Famix.Concretisation();
|
|
1177
|
+
|
|
1178
|
+
fmxConcretisation.setConcreteEntity(conEntity);
|
|
1179
|
+
fmxConcretisation.setGenericEntity(genEntity);
|
|
1180
|
+
this.fmxElementObjectMap.set(fmxConcretisation,null);
|
|
1181
|
+
this.famixRep.addElement(fmxConcretisation);
|
|
1182
|
+
const parameterConcretisation = this.createFamixParameterConcrestisation(fmxConcretisation);
|
|
1183
|
+
|
|
1184
|
+
return fmxConcretisation;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Creates a Famix concretisation
|
|
1189
|
+
* @param concretisation A FamixConcretisation
|
|
1190
|
+
* @returns The Famix model of the ParameterConcrestisation
|
|
1191
|
+
*/
|
|
1192
|
+
public createFamixParameterConcrestisation(concretisation: Famix.Concretisation): Famix.ParameterConcretisation {
|
|
1193
|
+
const conClass = concretisation.getConcreteEntity();
|
|
1194
|
+
const genClass = concretisation.getGenericEntity();
|
|
1195
|
+
const parameterConcretisations = this.famixRep._getAllEntitiesWithType("ParameterConcretisation");
|
|
1196
|
+
const concreteParameters = conClass.getConcreteParameters();
|
|
1197
|
+
const genericParameters = genClass.getGenericParameters();
|
|
1198
|
+
|
|
1199
|
+
let conClassTypeParametersIterator = concreteParameters.values();
|
|
1200
|
+
let genClassTypeParametersIterator = genericParameters.values();
|
|
1201
|
+
let fmxParameterConcretisation : Famix.ParameterConcretisation;
|
|
1202
|
+
|
|
1203
|
+
for (let i = 0; i < genericParameters.size; i++) {
|
|
1204
|
+
const conClassTypeParameter = conClassTypeParametersIterator.next().value;
|
|
1205
|
+
const genClassTypeParameter = genClassTypeParametersIterator.next().value;
|
|
1206
|
+
let createParameterConcretisation : boolean = true;
|
|
1207
|
+
if(conClassTypeParameter && genClassTypeParameter && conClassTypeParameter.getName() != genClassTypeParameter.getName()){
|
|
1208
|
+
parameterConcretisations.forEach((param : Famix.ParameterConcretisation) => {
|
|
1209
|
+
if (conClassTypeParameter.getName() == param.getConcreteParameter().getName() && genClassTypeParameter.getName() == param.getGenericParameter().getName()) {
|
|
1210
|
+
createParameterConcretisation = false;
|
|
1211
|
+
fmxParameterConcretisation = param;
|
|
1212
|
+
}
|
|
1213
|
+
})
|
|
1214
|
+
if (createParameterConcretisation) {
|
|
1215
|
+
fmxParameterConcretisation = new Famix.ParameterConcretisation();
|
|
1216
|
+
fmxParameterConcretisation.setGenericParameter(genClassTypeParameter);
|
|
1217
|
+
fmxParameterConcretisation.setConcreteParameter(conClassTypeParameter);
|
|
1218
|
+
fmxParameterConcretisation.addConcretisation(concretisation);
|
|
1219
|
+
this.fmxElementObjectMap.set(fmxParameterConcretisation,null);
|
|
1220
|
+
} else {
|
|
1221
|
+
fmxParameterConcretisation.addConcretisation(concretisation);
|
|
1222
|
+
}
|
|
1223
|
+
this.famixRep.addElement(fmxParameterConcretisation);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
return fmxParameterConcretisation;
|
|
1228
|
+
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/**
|
|
1232
|
+
* Creates a Famix concretisation between two classes or two interfaces
|
|
1233
|
+
* @param element A class or an Interface
|
|
1234
|
+
*/
|
|
1235
|
+
public createFamixConcretisationClassOrInterfaceSpecialisation(element: ClassDeclaration | InterfaceDeclaration){
|
|
1236
|
+
|
|
1237
|
+
const superEntity = element.getExtends();
|
|
1238
|
+
let superEntityArray;
|
|
1239
|
+
if (superEntity){
|
|
1240
|
+
superEntityArray = Array.isArray(superEntity) ? superEntity : [superEntity];
|
|
1241
|
+
}
|
|
1242
|
+
if (superEntityArray && superEntityArray.length > 0) {
|
|
1243
|
+
superEntityArray.forEach(entity => {
|
|
1244
|
+
let entityIsGeneric;
|
|
1245
|
+
const superEntitySymbol = entity.getExpression().getSymbolOrThrow();
|
|
1246
|
+
let superEntityDeclaration;
|
|
1247
|
+
if (superEntity instanceof ExpressionWithTypeArguments) {
|
|
1248
|
+
superEntityDeclaration = superEntitySymbol.getDeclarations()[0].asKind(ts.SyntaxKind.ClassDeclaration);
|
|
1249
|
+
} else {
|
|
1250
|
+
superEntityDeclaration = superEntitySymbol.getDeclarations()[0].asKind(ts.SyntaxKind.InterfaceDeclaration);
|
|
1251
|
+
}
|
|
1252
|
+
if (superEntityDeclaration) {
|
|
1253
|
+
entityIsGeneric = superEntityDeclaration.getTypeParameters().length > 0;
|
|
1254
|
+
}
|
|
1255
|
+
if (entityIsGeneric) {
|
|
1256
|
+
let EntityDeclaration;
|
|
1257
|
+
let genEntity;
|
|
1258
|
+
if (superEntity instanceof ExpressionWithTypeArguments) {
|
|
1259
|
+
EntityDeclaration = entity.getExpression().getSymbol().getDeclarations()[0] as ClassDeclaration;
|
|
1260
|
+
genEntity = this.createOrGetFamixClass(EntityDeclaration) as Famix.ParametricClass;
|
|
1261
|
+
} else {
|
|
1262
|
+
EntityDeclaration = entity.getExpression().getSymbol().getDeclarations()[0] as InterfaceDeclaration;
|
|
1263
|
+
genEntity = this.createOrGetFamixInterface(EntityDeclaration) as Famix.ParametricInterface;
|
|
1264
|
+
}
|
|
1265
|
+
const genParams = EntityDeclaration.getTypeParameters().map((param) => param.getText());
|
|
1266
|
+
const args = element.getHeritageClauses()[0].getTypeNodes()[0].getTypeArguments()
|
|
1267
|
+
const conParams = element.getHeritageClauses()[0].getTypeNodes()[0].getTypeArguments().map((param) => param.getText());
|
|
1268
|
+
if (!Helpers.arraysAreEqual(conParams,genParams)) {
|
|
1269
|
+
let conEntity;
|
|
1270
|
+
conEntity = this.createOrGetFamixConcreteElement(genEntity,EntityDeclaration,args);
|
|
1271
|
+
const concretisations = this.famixRep._getAllEntitiesWithType("Concretisation");
|
|
1272
|
+
let createConcretisation : boolean = true;
|
|
1273
|
+
concretisations.forEach((conc : Famix.Concretisation) => {
|
|
1274
|
+
if (genEntity.getFullyQualifiedName() == conc.getGenericEntity().getFullyQualifiedName() && conc.getConcreteEntity().getFullyQualifiedName() == conEntity.getFullyQualifiedName()){
|
|
1275
|
+
createConcretisation = false;
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
if (createConcretisation) {
|
|
1280
|
+
const fmxConcretisation : Famix.Concretisation = this.createFamixConcretisation(conEntity,genEntity);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* Creates a Famix concretisation between a class and its instanciations
|
|
1291
|
+
* @param cls A class
|
|
1292
|
+
*/
|
|
1293
|
+
public createFamixConcretisationGenericInstantiation(cls: ClassDeclaration){
|
|
1294
|
+
|
|
1295
|
+
const isGeneric = cls.getTypeParameters().length > 0;
|
|
1296
|
+
if (isGeneric) {
|
|
1297
|
+
const instances = cls.getSourceFile().getDescendantsOfKind(ts.SyntaxKind.NewExpression)
|
|
1298
|
+
.filter(newExpr => {
|
|
1299
|
+
const expression = newExpr.getExpression();
|
|
1300
|
+
return expression.getText() === cls.getName();
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
instances.forEach(instance => {
|
|
1304
|
+
const instanceIsGeneric = instance.getTypeArguments().length > 0;
|
|
1305
|
+
if (instanceIsGeneric) {
|
|
1306
|
+
const conParams = instance.getTypeArguments().map((param) => param.getText());
|
|
1307
|
+
const genEntity = this.createOrGetFamixClass(cls) as Famix.ParametricClass;
|
|
1308
|
+
const genParams = cls.getTypeParameters().map((param) => param.getText());
|
|
1309
|
+
if (!Helpers.arraysAreEqual(conParams,genParams)) {
|
|
1310
|
+
let conEntity;
|
|
1311
|
+
conEntity = this.createOrGetFamixConcreteElement(genEntity,cls,instance.getTypeArguments());
|
|
1312
|
+
const concretisations = this.famixRep._getAllEntitiesWithType("Concretisation");
|
|
1313
|
+
let createConcretisation : boolean = true;
|
|
1314
|
+
concretisations.forEach((conc : Famix.Concretisation) => {
|
|
1315
|
+
if (genEntity.getFullyQualifiedName() == conc.getGenericEntity().getFullyQualifiedName() && conc.getConcreteEntity().getFullyQualifiedName() == conEntity.getFullyQualifiedName()){
|
|
1316
|
+
createConcretisation = false;
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
if (createConcretisation) {
|
|
1321
|
+
const fmxConcretisation : Famix.Concretisation = this.createFamixConcretisation(conEntity,genEntity);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
})
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/**
|
|
1330
|
+
* Creates a Famix concretisation between a class and its instanciations
|
|
1331
|
+
* @param func A function
|
|
1332
|
+
*/
|
|
1333
|
+
public createFamixConcretisationFunctionInstantiation(element: FunctionDeclaration | MethodDeclaration){
|
|
1334
|
+
const isGeneric = element.getTypeParameters().length > 0;
|
|
1335
|
+
if (isGeneric) {
|
|
1336
|
+
const genParams = element.getTypeParameters().map(param => param.getText());
|
|
1337
|
+
const uses = element.findReferencesAsNodes();
|
|
1338
|
+
uses.forEach(usage => {
|
|
1339
|
+
let currentNode = usage;
|
|
1340
|
+
|
|
1341
|
+
while (currentNode) {
|
|
1342
|
+
if (currentNode.getKind() === SyntaxKind.CallExpression) {
|
|
1343
|
+
const callExpression = currentNode.asKind(SyntaxKind.CallExpression);
|
|
1344
|
+
const instanceIsGeneric = callExpression.getTypeArguments().length > 0;
|
|
1345
|
+
if (instanceIsGeneric) {
|
|
1346
|
+
const args = callExpression.getTypeArguments();
|
|
1347
|
+
const conParams = callExpression.getTypeArguments().map(param => param.getText());
|
|
1348
|
+
if (!Helpers.arraysAreEqual(conParams,genParams)) {
|
|
1349
|
+
let genElement;
|
|
1350
|
+
if(element instanceof FunctionDeclaration){
|
|
1351
|
+
genElement = this.createOrGetFamixFunction(element,0) as Famix.ParametricFunction;
|
|
1352
|
+
} else {
|
|
1353
|
+
genElement = this.createOrGetFamixMethod(element,0) as Famix.ParametricMethod;
|
|
1354
|
+
}
|
|
1355
|
+
let concElement;
|
|
1356
|
+
concElement = this.createOrGetFamixConcreteElement(genElement,element,args);
|
|
1357
|
+
const concretisations = this.famixRep._getAllEntitiesWithType("Concretisation");
|
|
1358
|
+
let createConcretisation : boolean = true;
|
|
1359
|
+
concretisations.forEach((conc : Famix.Concretisation) => {
|
|
1360
|
+
if (genElement.getFullyQualifiedName() == conc.getGenericEntity().getFullyQualifiedName() && conc.getConcreteEntity().getFullyQualifiedName() == concElement.getFullyQualifiedName()){
|
|
1361
|
+
createConcretisation = false;
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
if (createConcretisation) {
|
|
1366
|
+
const fmxConcretisation : Famix.Concretisation = this.createFamixConcretisation(concElement,genElement);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
break;
|
|
1371
|
+
}
|
|
1372
|
+
// Remonter à l'élément parent (utile si le nœud de référence est un enfant)
|
|
1373
|
+
currentNode = currentNode.getParent();
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Creates a Famix concretisation between a class and an interface
|
|
1381
|
+
* @param cls A class
|
|
1382
|
+
*/
|
|
1383
|
+
public createFamixConcretisationInterfaceClass(cls: ClassDeclaration){
|
|
1384
|
+
|
|
1385
|
+
const superInterfaces = cls.getImplements();
|
|
1386
|
+
superInterfaces.forEach(interfaceType => {
|
|
1387
|
+
const interfaceIsGeneric = interfaceType.getTypeArguments().length>0;
|
|
1388
|
+
if (interfaceIsGeneric) {
|
|
1389
|
+
const interfaceDeclaration = interfaceType.getExpression().getSymbol().getDeclarations()[0] as InterfaceDeclaration;
|
|
1390
|
+
const genParams = interfaceDeclaration.getTypeParameters().map((param) => param.getText());
|
|
1391
|
+
const conParams = cls.getHeritageClauses()[0].getTypeNodes()[0].getTypeArguments().map((param) => param.getText());
|
|
1392
|
+
const args = cls.getHeritageClauses()[0].getTypeNodes()[0].getTypeArguments();
|
|
1393
|
+
if (!Helpers.arraysAreEqual(conParams,genParams)) {
|
|
1394
|
+
const genInterface = this.createOrGetFamixInterface(interfaceDeclaration) as Famix.ParametricInterface;
|
|
1395
|
+
const conInterface = this.createOrGetFamixConcreteElement(genInterface,interfaceDeclaration,args);
|
|
1396
|
+
const concretisations = this.famixRep._getAllEntitiesWithType("Concretisation");
|
|
1397
|
+
let createConcretisation : boolean = true;
|
|
1398
|
+
concretisations.forEach((conc : Famix.Concretisation) => {
|
|
1399
|
+
if (genInterface.getFullyQualifiedName() == conc.getGenericEntity().getFullyQualifiedName() && conc.getConcreteEntity().getFullyQualifiedName() == conInterface.getFullyQualifiedName()){
|
|
1400
|
+
createConcretisation = false;
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
if (createConcretisation) {
|
|
1405
|
+
const fmxConcretisation : Famix.Concretisation = this.createFamixConcretisation(conInterface,genInterface);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* Creates a Famix concretisation between an interface and a Type
|
|
1414
|
+
* @param element A variable or a function
|
|
1415
|
+
* @param inter An interface
|
|
1416
|
+
*/
|
|
1417
|
+
public createFamixConcretisationTypeInstanciation(element: InterfaceDeclaration | ClassDeclaration){
|
|
1418
|
+
|
|
1419
|
+
const isGeneric = element.getTypeParameters().length > 0;
|
|
1420
|
+
if (isGeneric) {
|
|
1421
|
+
const genParams = element.getTypeParameters().map(param => param.getText());
|
|
1422
|
+
const uses = element.findReferencesAsNodes();
|
|
1423
|
+
uses.forEach(use => {
|
|
1424
|
+
let parentNode = use.getParent();
|
|
1425
|
+
while (parentNode) {
|
|
1426
|
+
if (parentNode.getKind() === SyntaxKind.TypeReference) {
|
|
1427
|
+
const typeReferenceNode = parentNode.asKind(SyntaxKind.TypeReference);
|
|
1428
|
+
const typeReferenceNodeIsGeneric = typeReferenceNode.getTypeArguments().length > 0;
|
|
1429
|
+
if (typeReferenceNodeIsGeneric) {}
|
|
1430
|
+
const args = typeReferenceNode.getTypeArguments();
|
|
1431
|
+
const conParams = typeReferenceNode.getTypeArguments().map(param => param.getText());
|
|
1432
|
+
if (!Helpers.arraysAreEqual(conParams,genParams)) {
|
|
1433
|
+
let genElement;
|
|
1434
|
+
if(element instanceof ClassDeclaration){
|
|
1435
|
+
genElement = this.createOrGetFamixClass(element) as Famix.ParametricClass;
|
|
1436
|
+
} else {
|
|
1437
|
+
genElement = this.createOrGetFamixInterface(element) as Famix.ParametricInterface;
|
|
1438
|
+
}
|
|
1439
|
+
let concElement;
|
|
1440
|
+
concElement = this.createOrGetFamixConcreteElement(genElement,element,args);
|
|
1441
|
+
const concretisations = this.famixRep._getAllEntitiesWithType("Concretisation");
|
|
1442
|
+
let createConcretisation : boolean = true;
|
|
1443
|
+
concretisations.forEach((conc : Famix.Concretisation) => {
|
|
1444
|
+
if (genElement.getFullyQualifiedName() == conc.getGenericEntity().getFullyQualifiedName() && conc.getConcreteEntity().getFullyQualifiedName() == concElement.getFullyQualifiedName()){
|
|
1445
|
+
createConcretisation = false;
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
if (createConcretisation) {
|
|
1450
|
+
const fmxConcretisation : Famix.Concretisation = this.createFamixConcretisation(concElement,genElement);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
parentNode = parentNode.getParent();
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
912
1461
|
public convertToRelativePath(absolutePath: string, absolutePathProject: string) {
|
|
913
1462
|
return absolutePath.replace(absolutePathProject, "").slice(1);
|
|
914
1463
|
}
|
|
915
|
-
}
|
|
1464
|
+
}
|