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

moosetechnology / Famix-Value / 10251242118

05 Aug 2024 03:02PM UTC coverage: 25.456% (-2.4%) from 27.828%
10251242118

push

github

Gabriel-Darbord
Merge 1a94bd0eb

0 of 148 new or added lines in 6 files covered. (0.0%)

343 existing lines in 7 files now uncovered.

754 of 2962 relevant lines covered (25.46%)

0.25 hits per line

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

37.18
/src/Famix-Value-Exporter/FamixValue2FASTJavaVisitor.class.st
1
"
2
A visitor to export a FamixValue model to FASTJava.
3
The generated code is a block statement with a variable declared for each value.
4

5
Object attributes are initialized by finding the corresponding setters.
6
Collections and Dictionaries are constructed with the methods `add(element)` and `put(key, value)` respectively.
7

8
When exporting a `FamixValueOfObjectAttribute`, if the setter for its `FamixTAttribute` cannot be found, it is set using the Java Reflection API.
9
All attributes that fall into this category are added as `markedForReflection`.
10
"
11
Class {
12
        #name : #FamixValue2FASTJavaVisitor,
13
        #superclass : #FamixValue2ASTVisitor,
14
        #instVars : [
15
                'builder',
16
                'constructorCache',
17
                'staticAttributesCache',
18
                'objectExportStrategy',
19
                'reflections'
20
        ],
21
        #category : #'Famix-Value-Exporter-Visitors'
22
}
23

24
{ #category : #private }
25
FamixValue2FASTJavaVisitor >> addAttributesFrom: object asArgumentsTo: invocation usingConstructor: constructor [
×
26

×
27
        (constructorCache
×
28
                 at: constructor
×
29
                 ifAbsentPut: [ constructor mapConstructorParametersToAttributes ])
×
30
                withIndexDo: [ :paramAttribute :index |
×
31
                        invocation addArgument: (paramAttribute
×
32
                                         ifNil: [ "constructor parameter is not mapped to an attribute"
×
33
                                                 (constructor parameters at: index) declaredType
×
34
                                                         asFASTJavaDefaultValueOn: self model ]
×
35
                                         ifNotNil: [
×
36
                                                 object value
×
37
                                                         detect: [ :objAttribute | "find the matching value attribute"
×
38
                                                                 objAttribute attribute == paramAttribute ]
×
39
                                                         ifFound: [ :objAttribute | "dispatch for var naming context"
×
40
                                                                 objectExportStrategy
×
41
                                                                         makeVariableExpression: objAttribute value
×
42
                                                                         on: self ]
×
43
                                                         ifNone: [ "the object does not have the attribute set"
×
44
                                                                 paramAttribute declaredType asFASTJavaDefaultValueOn:
×
45
                                                                         self model ] ]) ]
×
46
]
×
47

48
{ #category : #accessing }
49
FamixValue2FASTJavaVisitor >> builder [
1✔
50

1✔
51
        ^ builder ifNil: [ builder := FASTJavaBuilder new model: self model ]
1✔
52
]
1✔
53

54
{ #category : #private }
55
FamixValue2FASTJavaVisitor >> constructObject: object [
1✔
56

1✔
57
        | constructor invocation |
1✔
58
        constructor := self findConstructorFor: object.
1✔
59
        self reflections
1✔
60
                at: constructor
1✔
61
                ifPresent: [ :varName | "reflective constructor call, the variable contains the Constructor object"
1✔
62
                        invocation := model newMethodInvocation name: 'instantiate'.
1✔
63
                        invocation addArgument: (model newVariableExpression name: varName).
1✔
64
                        (self statementBlock addStatement: self model newVarDeclStatement)
1✔
65
                                type: (self builder referType: object type);
1✔
66
                                addDeclarator: (model newVariableDeclarator
1✔
67
                                                 variable: (self makeVariableExpression: object);
1✔
68
                                                 expression: invocation) ]
1✔
69
                ifAbsent: [ "regular constructor call"
1✔
70
                        invocation := (self statementBlock addStatement:
1✔
71
                                               (self makeVarDeclStatement: object)) declarators
1✔
72
                                              first expression ].
1✔
73
        "call with arguments to match constructor parameters"
1✔
74
        constructor parameters ifNotEmpty: [
1✔
75
                self
1✔
76
                        addAttributesFrom: object
1✔
77
                        asArgumentsTo: invocation
1✔
78
                        usingConstructor: constructor ]
1✔
79
]
1✔
80

81
{ #category : #private }
UNCOV
82
FamixValue2FASTJavaVisitor >> ensureReflection [
×
UNCOV
83
        "Ensure that the infrastructure needed to use reflection is generated.
×
UNCOV
84
        A static method called `initializeReflection` is created and will be populated by calls to `ensureReflectionField:` and `ensureReflectionConstructor:`.
×
UNCOV
85
        To handle exceptions that can be thrown by these operations, a static initializer calls this method with a trycatch.
×
UNCOV
86
        Finally, the convenience methods `setField` and `instantiate` are created to handle exceptions during reflexive operations: .
×
UNCOV
87
        Return the statement block of `initializeReflection` for callers to populate."
×
UNCOV
88

×
UNCOV
89
        | declarations declaration initStatementBlock |
×
UNCOV
90
        declarations := self objectExportStrategy declarations. "does not work for inline strategy..."
×
UNCOV
91
        self reflections ifNotEmpty: [
×
UNCOV
92
                ^ (declarations at: -3) statementBlock ].
×
UNCOV
93

×
UNCOV
94
        "static {
×
UNCOV
95
                try {
×
UNCOV
96
                        initializeReflection();
×
UNCOV
97
                } catch (NoSuchFieldException | SecurityException e) {
×
UNCOV
98
                        new RuntimeException(e);
×
UNCOV
99
                }
×
UNCOV
100
        }"
×
UNCOV
101
        declaration := self model newInitializer isStatic: true.
×
UNCOV
102
        declaration attributeAt: 'order' put: -4.
×
UNCOV
103
        declarations at: -4 put: declaration.
×
UNCOV
104
        declaration statementBlock:
×
UNCOV
105
                (model newStatementBlock statements: { (model newTryCatchStatement
×
UNCOV
106
                                  try: (model newStatementBlock statements:
×
UNCOV
107
                                                           { (model newExpressionStatement expression:
×
UNCOV
108
                                                                            (model newMethodInvocation name: 'initializeReflection')) });
×
UNCOV
109
                                  catches: { (model newCatchPartStatement
×
UNCOV
110
                                                   catchedTypes: {
×
UNCOV
111
                                                                   (model newClassTypeExpression typeName:
×
UNCOV
112
                                                                                    (model newTypeName name: 'NoSuchFieldException')).
×
UNCOV
113
                                                                   (model newClassTypeExpression typeName:
×
UNCOV
114
                                                                                    (model newTypeName name: 'SecurityException')).
×
UNCOV
115
                                                                   (model newClassTypeExpression typeName:
×
UNCOV
116
                                                                                    (model newTypeName name: 'NoSuchMethodException')) };
×
UNCOV
117
                                                   body: (model newStatementBlock statements:
×
UNCOV
118
                                                                            { (model newThrowStatement expression:
×
UNCOV
119
                                                                                             (model newNewExpression
×
UNCOV
120
                                                                                                      type: (model newClassTypeExpression typeName:
×
UNCOV
121
                                                                                                                               (model newTypeName name: 'RuntimeException'));
×
UNCOV
122
                                                                                                      arguments:
×
UNCOV
123
                                                                                                              { (model newVariableExpression name: 'e') })) });
×
UNCOV
124
                                                   parameter: (model newVariableExpression name: 'e')) }) }).
×
UNCOV
125

×
UNCOV
126
        "private static void initializeReflection() throws NoSuchFieldException, SecurityException {
×
UNCOV
127
                // fields will be obtained and set as accessible here
×
UNCOV
128
        }"
×
UNCOV
129
        declaration := model newMethodEntity name: 'initializeReflection'.
×
UNCOV
130
        declaration attributeAt: 'order' put: -3.
×
UNCOV
131
        declarations at: -3 put: declaration.
×
UNCOV
132
        declaration
×
UNCOV
133
                type: (model newVoidTypeExpression name: 'void');
×
UNCOV
134
                modifiers: {
×
UNCOV
135
                                (model newModifier token: 'private').
×
UNCOV
136
                                (model newModifier token: 'static') };
×
UNCOV
137
                throws: {
×
UNCOV
138
                                (model newClassTypeExpression typeName:
×
UNCOV
139
                                                 (model newTypeName name: 'NoSuchFieldException')).
×
UNCOV
140
                                (model newClassTypeExpression typeName:
×
UNCOV
141
                                                 (model newTypeName name: 'SecurityException')).
×
UNCOV
142
                                (model newClassTypeExpression typeName:
×
UNCOV
143
                                                 (model newTypeName name: 'NoSuchMethodException')) };
×
UNCOV
144
                statementBlock: (initStatementBlock := model newStatementBlock).
×
UNCOV
145

×
146
        "public static void setField(Object object, Field field, Object value) {
×
147
                try {
×
148
                        field.set(object, value);
×
149
                } catch (IllegalAccessException e) {
×
150
                        throw new RuntimeException(e);
×
151
                }
×
152
        }"
×
153
        declaration := model newMethodEntity name: 'setField'.
×
154
        declaration attributeAt: 'order' put: -2.
×
155
        declarations at: -2 put: declaration.
×
156
        declaration
×
157
                type: (model newVoidTypeExpression name: 'void');
×
158
                parameters: {
×
159
                                (model newParameter
×
160
                                         variable: (model newVariableExpression name: 'object');
×
161
                                         type: (model newClassTypeExpression typeName:
×
162
                                                                  (model newTypeName name: 'Object'))).
×
UNCOV
163
                                (model newParameter
×
UNCOV
164
                                         variable: (model newVariableExpression name: 'field');
×
165
                                         type: (model newClassTypeExpression typeName:
×
166
                                                                  (model newTypeName name: 'Field'))).
×
167
                                (model newParameter
×
168
                                         variable: (model newVariableExpression name: 'value');
×
169
                                         type: (model newClassTypeExpression typeName:
×
170
                                                                  (model newTypeName name: 'Object'))) };
×
171
                modifiers: {
×
172
                                (model newModifier token: 'public').
×
173
                                (model newModifier token: 'static') };
×
174
                statementBlock:
×
175
                        (model newStatementBlock statements: { (model newTryCatchStatement
×
176
                                          try: (model newStatementBlock statements:
×
177
                                                                   { (model newExpressionStatement expression:
×
178
                                                                                    (model newMethodInvocation
×
179
                                                                                             receiver: (model newVariableExpression name: 'field');
×
180
                                                                                             name: 'set';
×
181
                                                                                             arguments: {
×
182
                                                                                                             (model newVariableExpression name: 'object').
×
183
                                                                                                             (model newVariableExpression name: 'value') })) });
×
184
                                          catches: { (model newCatchPartStatement
×
185
                                                           catchedTypes: { (model newClassTypeExpression typeName:
×
186
                                                                                    (model newTypeName name: 'IllegalAccessException')) };
×
187
                                                           body: (model newStatementBlock statements:
×
188
                                                                                    { (model newThrowStatement expression:
×
189
                                                                                                     (model newNewExpression
×
190
                                                                                                              type: (model newClassTypeExpression typeName:
×
UNCOV
191
                                                                                                                                       (model newTypeName name: 'RuntimeException'));
×
UNCOV
192
                                                                                                              arguments:
×
UNCOV
193
                                                                                                                      { (model newVariableExpression name: 'e') })) });
×
UNCOV
194
                                                           parameter: (model newVariableExpression name: 'e')) }) }).
×
UNCOV
195

×
UNCOV
196
        "private static <T> T instantiate(Constructor<T> constructor, Object... arguments) {
×
UNCOV
197
                T instance;
×
UNCOV
198
                try {
×
UNCOV
199
                        instance = constructor.newInstance(arguments);
×
UNCOV
200
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
×
201
                        throw new RuntimeException(e);
×
202
                }
×
203
                return instance;
×
204
        }"
×
205
        declaration := model newMethodEntity name: 'instantiate'.
×
206
        declaration attributeAt: 'order' put: -1.
×
207
        declarations at: -1 put: declaration.
×
208
        declaration
×
209
                typeParameters: { (model newTypeParameterExpression name: 'T') };
×
210
                type:
×
211
                        (model newClassTypeExpression typeName:
×
212
                                         (model newTypeName name: 'T'));
×
UNCOV
213
                parameters: {
×
UNCOV
214
                                (model newParameter
×
215
                                         variable: (model newVariableExpression name: 'constructor');
×
216
                                         type: (model newClassTypeExpression
×
217
                                                          arguments: { (model newClassTypeExpression typeName:
×
218
                                                                                   (model newTypeName name: 'T')) };
×
219
                                                          typeName: (model newTypeName name: 'Constructor'))).
×
220
                                (model newParameter
×
221
                                         variable: (model newVariableExpression name: 'arguments');
×
222
                                         type: (model newClassTypeExpression typeName:
×
223
                                                                  (model newTypeName name: 'Object'));
×
224
                                         hasVariableArguments: true) };
×
225
                modifiers: {
×
226
                                (model newModifier token: 'private').
×
227
                                (model newModifier token: 'static') };
×
228
                statementBlock: (model newStatementBlock statements: {
×
229
                                         (model newVarDeclStatement
×
230
                                                  type:
×
231
                                                          (model newClassTypeExpression typeName:
×
UNCOV
232
                                                                           (model newTypeName name: 'T'));
×
UNCOV
233
                                                  declarators: { (model newVariableDeclarator variable:
×
UNCOV
234
                                                                           (model newVariableExpression name: 'instance')) }).
×
UNCOV
235
                                         (model newTryCatchStatement
×
UNCOV
236
                                                  try: (model newStatementBlock statements:
×
UNCOV
237
                                                                           { (model newExpressionStatement expression:
×
UNCOV
238
                                                                                            (model newAssignmentExpression
×
UNCOV
239
                                                                                                     variable:
×
UNCOV
240
                                                                                                             (model newVariableExpression name: 'instance');
×
UNCOV
241
                                                                                                     expression: (model newMethodInvocation
×
UNCOV
242
                                                                                                                      receiver:
×
UNCOV
243
                                                                                                                              (model newIdentifier name: 'constructor');
×
UNCOV
244
                                                                                                                      name: 'newInstance';
×
UNCOV
245
                                                                                                                      arguments:
×
UNCOV
246
                                                                                                                              { (model newVariableExpression name: 'arguments') });
×
UNCOV
247
                                                                                                     operator: '=')) });
×
UNCOV
248
                                                  catches: { (model newCatchPartStatement
×
UNCOV
249
                                                                   catchedTypes: {
×
UNCOV
250
                                                                                   (model newClassTypeExpression typeName:
×
UNCOV
251
                                                                                                    (model newTypeName name: 'InstantiationException')).
×
UNCOV
252
                                                                                   (model newClassTypeExpression typeName:
×
UNCOV
253
                                                                                                    (model newTypeName name: 'IllegalAccessException')).
×
UNCOV
254
                                                                                   (model newClassTypeExpression typeName:
×
UNCOV
255
                                                                                                    (model newTypeName name: 'InvocationTargetException')) };
×
UNCOV
256
                                                                   body: (model newStatementBlock statements:
×
UNCOV
257
                                                                                            { (model newThrowStatement expression:
×
UNCOV
258
                                                                                                             (model newNewExpression
×
UNCOV
259
                                                                                                                      type: (model newClassTypeExpression typeName:
×
UNCOV
260
                                                                                                                                               (model newTypeName name: 'RuntimeException'));
×
UNCOV
261
                                                                                                                      arguments:
×
UNCOV
262
                                                                                                                              { (model newVariableExpression name: 'e') })) });
×
UNCOV
263
                                                                   parameter: (model newVariableExpression name: 'e')) }).
×
264
                                         (model newReturnStatement expression:
×
265
                                                  (model newVariableExpression name: 'instance')) }).
×
266

×
267
        ^ initStatementBlock
×
268
]
×
269

270
{ #category : #private }
271
FamixValue2FASTJavaVisitor >> ensureReflectionConstructor: aFamixJavaMethod [
×
272

×
273
        | declarations initStatementBlock varName |
×
274
        declarations := self objectExportStrategy declarations.
×
275
        initStatementBlock := self ensureReflection.
×
276
        varName := aFamixJavaMethod name asUppercase.
×
UNCOV
277
        self reflections at: aFamixJavaMethod put: varName.
×
UNCOV
278

×
UNCOV
279
        declarations
×
UNCOV
280
                at: varName
×
UNCOV
281
                ifPresent: [ "handle naming collisions, some ideas:
×
UNCOV
282
                                - use fully qualified type name (only when necessary?)
×
UNCOV
283
                                - use a HashMap to store the fields based on class and attribute name"
×
UNCOV
284
                        self shouldBeImplemented ]
×
UNCOV
285
                ifAbsentPut: [
×
UNCOV
286
                        model newVarDeclStatement
×
UNCOV
287
                                type: (model newClassTypeExpression
×
UNCOV
288
                                                 typeName: (model newTypeName name: 'Constructor');
×
UNCOV
289
                                                 arguments:
×
UNCOV
290
                                                         { (self builder referType: aFamixJavaMethod parentType) });
×
UNCOV
291
                                modifiers: {
×
UNCOV
292
                                                (model newModifier token: 'private').
×
UNCOV
293
                                                (model newModifier token: 'static') };
×
UNCOV
294
                                declarators: { (model newVariableDeclarator variable:
×
UNCOV
295
                                                 (model newVariableExpression name: varName)) } ].
×
UNCOV
296

×
UNCOV
297
        "add the code in `initializeReflection` to get the Field and set it as accessible:
×
UNCOV
298
        CLASSNAME = CLASS.class.getDeclaredConstructor(PARAMETER_CLASSES);
×
UNCOV
299
        CLASSNAME.setAccessible(true);"
×
UNCOV
300
        initStatementBlock addStatement:
×
UNCOV
301
                (model newExpressionStatement expression:
×
UNCOV
302
                         (model newAssignmentExpression
×
UNCOV
303
                                  variable: (model newVariableExpression name: varName);
×
UNCOV
304
                                  expression: (model newMethodInvocation
×
UNCOV
305
                                                   receiver: (model newClassProperty
×
UNCOV
306
                                                                    type:
×
UNCOV
307
                                                                            (self builder referType: aFamixJavaMethod parentType);
×
UNCOV
308
                                                                    fieldName: 'class');
×
UNCOV
309
                                                   name: 'getDeclaredConstructor';
×
UNCOV
310
                                                   arguments:
×
UNCOV
311
                                                           (aFamixJavaMethod sortedParameters collect: [ :parameter |
×
UNCOV
312
                                                                    model newClassProperty
×
313
                                                                            type: (self builder referType: parameter declaredType);
×
314
                                                                            fieldName: 'class' ]));
×
315
                                  operator: '=')).
×
316
        initStatementBlock addStatement:
×
UNCOV
317
                (model newExpressionStatement expression:
×
UNCOV
318
                         (model newMethodInvocation
×
UNCOV
319
                                  receiver: (model newVariableExpression name: varName);
×
UNCOV
320
                                  name: 'setAccessible';
×
UNCOV
321
                                  arguments: { (model newBooleanLiteral primitiveValue: 'true') }))
×
UNCOV
322
]
×
323

324
{ #category : #private }
UNCOV
325
FamixValue2FASTJavaVisitor >> ensureReflectionField: attribute [
×
UNCOV
326
        "Ensure an attribute exists to hold the java.lang.reflect.Field for the given attribute."
×
UNCOV
327

×
UNCOV
328
        ^ self reflections at: attribute attribute ifAbsentPut: [
×
UNCOV
329
                  | declarations initStatementBlock varName |
×
UNCOV
330
                  declarations := self objectExportStrategy declarations.
×
UNCOV
331
                  initStatementBlock := self ensureReflection.
×
UNCOV
332
                  varName := attribute attribute parentType name asUppercase , '_'
×
UNCOV
333
                             , attribute attribute name asUppercase.
×
UNCOV
334
                  declarations
×
UNCOV
335
                          at: varName
×
UNCOV
336
                          ifPresent: [ "handle naming collisions, some ideas:
×
UNCOV
337
                                - use fully qualified type name (only when necessary?)
×
UNCOV
338
                                - use a HashMap to store the fields based on class and attribute name"
×
UNCOV
339
                                  self shouldBeImplemented ]
×
UNCOV
340
                          ifAbsentPut: [
×
UNCOV
341
                                  model newVarDeclStatement
×
UNCOV
342
                                          type: (model newClassTypeExpression typeName:
×
UNCOV
343
                                                                   (model newTypeName name: 'Field'));
×
UNCOV
344
                                          modifiers: {
×
UNCOV
345
                                                          (model newModifier token: 'private').
×
UNCOV
346
                                                          (model newModifier token: 'static') };
×
UNCOV
347
                                          declarators: { (model newVariableDeclarator variable:
×
UNCOV
348
                                                                   (model newVariableExpression name: varName)) } ].
×
UNCOV
349

×
UNCOV
350
                  "add the code in `initializeReflection` to get the Field and set it as accessible:
×
UNCOV
351
                  CLASSNAME_FIELDNAME = CLASS.class.getDeclaredField(FIELDNAME);
×
UNCOV
352
                  CLASSNAME.setAccessible(true);"
×
UNCOV
353
                  initStatementBlock addStatement:
×
UNCOV
354
                          (model newExpressionStatement expression:
×
UNCOV
355
                                   (model newAssignmentExpression
×
UNCOV
356
                                            variable: (model newVariableExpression name: varName);
×
UNCOV
357
                                            expression: (model newMethodInvocation
×
UNCOV
358
                                                             receiver: (model newClassProperty
×
UNCOV
359
                                                                              type:
×
UNCOV
360
                                                                                      (self builder referType:
×
UNCOV
361
                                                                                                       attribute attribute parentType);
×
UNCOV
362
                                                                              fieldName: 'class');
×
UNCOV
363
                                                             name: 'getDeclaredField';
×
UNCOV
364
                                                             arguments:
×
UNCOV
365
                                                             { (model newStringLiteral primitiveValue:
×
UNCOV
366
                                                                      attribute attribute name) });
×
UNCOV
367
                                            operator: '=')).
×
UNCOV
368
                  initStatementBlock addStatement:
×
UNCOV
369
                          (model newExpressionStatement expression:
×
UNCOV
370
                                   (model newMethodInvocation
×
UNCOV
371
                                            receiver: (model newVariableExpression name: varName);
×
UNCOV
372
                                            name: 'setAccessible';
×
UNCOV
373
                                            arguments:
×
UNCOV
374
                                                    { (model newBooleanLiteral primitiveValue: 'true') })).
×
UNCOV
375
                  varName ]
×
UNCOV
376
]
×
377

378
{ #category : #private }
379
FamixValue2FASTJavaVisitor >> filterAttributesToSet: attributes for: object [
1✔
380
        "No need to set attributes that are set in the constructor."
1✔
381

1✔
382
        ^ constructorCache
1✔
383
                  at: object type
1✔
384
                  ifPresent: [ :constructor |
1✔
385
                          constructorCache
1✔
386
                                  at: constructor
1✔
387
                                  ifPresent: [ :constructorAttributes |
1✔
388
                                          attributes reject: [ :attribute |
1✔
389
                                                  constructorAttributes includes: attribute attribute ] ]
1✔
390
                                  ifAbsent: [ attributes ] ]
1✔
391
                  ifAbsent: [ attributes ]
1✔
392
]
1✔
393

394
{ #category : #private }
395
FamixValue2FASTJavaVisitor >> findConstructorFor: object [
1✔
396
        "Order all constructors according to attributes set and number of parameters, then choose best public one.
1✔
397
        If no constructor is explicitly declared, use the default constructor. Otherwise, rely on reflection."
1✔
398

1✔
399
        | type |
1✔
400
        type := object type.
1✔
401
        ^ constructorCache at: type ifAbsentPut: [
1✔
402
                  type constructorsOrderedByScore
1✔
403
                          ifEmpty: [ "use default constructor, this acts as a null object"
1✔
404
                                  FamixJavaMethod new ]
1✔
405
                          ifNotEmpty: [ :constructors |
1✔
406
                                  constructors
1✔
407
                                          detect: [ :constructor | constructor isPublic ]
1✔
408
                                          ifNone: [ "fallback to using reflection with constructor with best score"
1✔
409
                                                  | constructor |
1✔
410
                                                  constructor := constructors first.
1✔
411
                                                  self ensureReflectionConstructor: constructor.
1✔
412
                                                  constructor ] ] ]
1✔
413
]
1✔
414

415
{ #category : #private }
416
FamixValue2FASTJavaVisitor >> findStaticAttributeMatching: object [
1✔
417
        "Only try to find static attributes for object composed of only primitive values, for now."
1✔
418

1✔
419
        | type staticAttributes objAttributes |
1✔
420
        type := object type.
1✔
421
        ((objAttributes := object relevantAttributes) allSatisfy: [
1✔
422
                 :attribute | attribute value isOfPrimitiveType ]) ifFalse: [ ^ nil ].
1✔
423
        "eligible attributes are public, static, of the same type, and have an initializer expression; the conditions are ordered for maximum time efficiency"
1✔
424
        staticAttributes := staticAttributesCache at: type ifAbsentPut: [
1✔
425
                                    type attributes select: [ :attribute |
1✔
426
                                            attribute declaredType == object type and: [
1✔
427
                                                    attribute isStaticConstant ] ] ].
1✔
428
        staticAttributes ifEmpty: [ ^ nil ].
1✔
429
        "get a list of the object's attributes represented as source code literals"
1✔
430
        objAttributes := objAttributes collect: [ :objAttribute |
1✔
431
                                 objAttribute value type name = 'String'
1✔
432
                                         ifTrue: [ '"' , objAttribute value value , '"' ]
1✔
433
                                         ifFalse: [ objAttribute value value asString ] ].
1✔
434
        ^ staticAttributes
1✔
435
                  detect: [ :attribute |
1✔
436
                  attribute initializerMatchesValues: objAttributes ]
1✔
437
                  ifNone: nil
1✔
438
]
1✔
439

440
{ #category : #initialization }
441
FamixValue2FASTJavaVisitor >> initialize [
1✔
442

1✔
443
        constructorCache := IdentityDictionary new.
1✔
444
        staticAttributesCache := IdentityDictionary new
1✔
445
]
1✔
446

447
{ #category : #ast }
448
FamixValue2FASTJavaVisitor >> makeClassTypeExpression: typeName [
1✔
449

1✔
450
        ^ self model newClassTypeExpression typeName:
1✔
451
                  (model newTypeName name: typeName)
1✔
452
]
1✔
453

454
{ #category : #ast }
UNCOV
455
FamixValue2FASTJavaVisitor >> makeHelper [
×
UNCOV
456
        "The helper should always be generated, regardless of strategy.
×
UNCOV
457
        This method must be called after all of the other value exports are done."
×
UNCOV
458

×
UNCOV
459
        | helperClass compilationUnit |
×
UNCOV
460
        helperClass := self makeHelperClass.
×
UNCOV
461
        (compilationUnit := self model newCompilationUnit)
×
UNCOV
462
                packageDeclaration: (model newPackageDeclaration qualifiedName:
×
UNCOV
463
                                         (model newQualifiedName name: 'fr.evref.modest'));
×
UNCOV
464
                importDeclarations: self builder makeImportDeclarations;
×
UNCOV
465
                addClassDeclaration: helperClass.
×
UNCOV
466

×
UNCOV
467
        reflections ifNotNil: [
×
UNCOV
468
                compilationUnit
×
UNCOV
469
                        addImportDeclaration: (model newImportDeclaration qualifiedName:
×
UNCOV
470
                                                 (model newQualifiedName name: 'java.lang.reflect.Field'));
×
UNCOV
471
                        addImportDeclaration: (model newImportDeclaration qualifiedName:
×
UNCOV
472
                                                 (model newQualifiedName name: 'java.lang.reflect.Constructor'));
×
UNCOV
473
                        addImportDeclaration: (model newImportDeclaration qualifiedName:
×
UNCOV
474
                                                 (model newQualifiedName name:
×
UNCOV
475
                                                                  'java.lang.reflect.InvocationTargetException')) ].
×
UNCOV
476

×
UNCOV
477
        self objectExportStrategy addToHelper: helperClass
×
UNCOV
478
]
×
479

480
{ #category : #ast }
UNCOV
481
FamixValue2FASTJavaVisitor >> makeHelperClass [
×
UNCOV
482
        "The helper class should not be instantiated so it has a private constructor."
×
UNCOV
483

×
UNCOV
484
        ^ self model newClassDeclaration
×
UNCOV
485
                  name: 'ModestHelper';
×
UNCOV
486
                  addModifier: (model newModifier token: 'public');
×
UNCOV
487
                  addDeclaration: (model newMethodEntity
×
UNCOV
488
                                   name: 'ModestHelper';
×
UNCOV
489
                                   modifiers: { (model newModifier token: 'private') };
×
UNCOV
490
                                   statementBlock: model newStatementBlock);
×
UNCOV
491
                  yourself
×
UNCOV
492
]
×
493

494
{ #category : #ast }
495
FamixValue2FASTJavaVisitor >> makeNewExpression: object [
1✔
496

1✔
497
        ^ self model newNewExpression type:
1✔
498
                  (object asFASTJavaTypeExpressionOn: self)
1✔
499
        "(self makeClassTypeExpression: object type concreteTypeName)"
1✔
500
]
1✔
501

502
{ #category : #ast }
UNCOV
503
FamixValue2FASTJavaVisitor >> makeReflectionFieldGetter: attribute [
×
UNCOV
504

×
UNCOV
505
        ^ self model newMethodInvocation
×
UNCOV
506
                  receiver: (model newClassProperty
×
UNCOV
507
                                   type:
×
UNCOV
508
                                           (self makeClassTypeExpression: attribute object type typeName);
×
UNCOV
509
                                   fieldName: 'class');
×
UNCOV
510
                  name: 'getDeclaredField';
×
UNCOV
511
                  addArgument:
×
UNCOV
512
                  (model newStringLiteral primitiveValue: attribute attribute name);
×
UNCOV
513
                  yourself
×
UNCOV
514
]
×
515

516
{ #category : #ast }
UNCOV
517
FamixValue2FASTJavaVisitor >> makeReflectionSetterInvocation: attribute [
×
UNCOV
518
        "Use reflection to set an attribute on an object."
×
UNCOV
519

×
UNCOV
520
        | fieldName |
×
UNCOV
521
        fieldName := self ensureReflectionField: attribute.
×
UNCOV
522
        self statementBlock addStatement:
×
UNCOV
523
                (self model newExpressionStatement expression:
×
UNCOV
524
                         (model newMethodInvocation
×
UNCOV
525
                                  name: 'setField';
×
UNCOV
526
                                  arguments: {
×
UNCOV
527
                                                  (self makeVariableExpression: attribute object).
×
UNCOV
528
                                                  (model newVariableExpression name: fieldName).
×
UNCOV
529
                                                  (model newVariableExpression name: attribute value varName) }))
×
UNCOV
530
]
×
531

532
{ #category : #ast }
533
FamixValue2FASTJavaVisitor >> makeSetterInvocation: setter for: attribute [
1✔
534

1✔
535
        self
1✔
536
                makeSetterInvocation: setter
1✔
537
                for: attribute
1✔
538
                named: (self varNameFor: attribute value)
1✔
539
]
1✔
540

541
{ #category : #ast }
542
FamixValue2FASTJavaVisitor >> makeSetterInvocation: setter for: attribute named: aString [
1✔
543

1✔
544
        self statementBlock addStatement:
1✔
545
                (self model newExpressionStatement expression:
1✔
546
                         (model newMethodInvocation
1✔
547
                                  receiver: (self makeVariableExpression: attribute object);
1✔
548
                                  name: setter name;
1✔
549
                                  addArgument: (model newVariableExpression name: aString);
1✔
550
                                  famixMethod: setter))
1✔
551
]
1✔
552

553
{ #category : #ast }
554
FamixValue2FASTJavaVisitor >> makeVarDeclStatement: value [
1✔
555

1✔
556
        ^ self model newVarDeclStatement
1✔
557
                  type: (value asFASTJavaTypeExpressionOn: self);
1✔
558
                  addDeclarator: (self makeVariableDeclarator: value);
1✔
559
                  yourself
1✔
560
]
1✔
561

562
{ #category : #ast }
UNCOV
563
FamixValue2FASTJavaVisitor >> makeVarDeclStatement: object usingStaticAttribute: attribute [
×
UNCOV
564
        "Declare a variable for object, initialized with the value of the given static attribute.
×
UNCOV
565
        For example: MyClass myClass = MyClass.MY_STATIC_ATTRIBUTE;"
×
UNCOV
566

×
UNCOV
567
        self statementBlock addStatement: (model newVarDeclStatement
×
UNCOV
568
                         type: (object asFASTJavaTypeExpressionOn: self);
×
UNCOV
569
                         addDeclarator: (model newVariableDeclarator
×
UNCOV
570
                                          variable: (self makeVariableExpression: object);
×
UNCOV
571
                                          expression: (model newClassProperty
×
UNCOV
572
                                                           type: (self makeClassTypeExpression: object type name);
×
UNCOV
573
                                                           fieldName: attribute name));
×
UNCOV
574
                         yourself)
×
UNCOV
575
]
×
576

577
{ #category : #ast }
578
FamixValue2FASTJavaVisitor >> makeVariableDeclarator: value [
1✔
579

1✔
580
        ^ self model newVariableDeclarator
1✔
581
                  variable: (self makeVariableExpression: value);
1✔
582
                  expression: (value asFASTJavaExpressionOn: self)
1✔
583
]
1✔
584

585
{ #category : #ast }
586
FamixValue2FASTJavaVisitor >> makeVariableExpression: value [
1✔
587

1✔
588
        ^ self model newVariableExpression name: (self varNameFor: value)
1✔
589
]
1✔
590

591
{ #category : #accessing }
592
FamixValue2FASTJavaVisitor >> model [
1✔
593

1✔
594
        ^ model ifNil: [ model := FASTJavaModel new ]
1✔
595
]
1✔
596

597
{ #category : #accessing }
598
FamixValue2FASTJavaVisitor >> objectExportStrategy [
1✔
599

1✔
600
        ^ objectExportStrategy ifNil: [
1✔
601
                  objectExportStrategy := FamixValueInlineObjectExportStrategy new ]
1✔
602
]
1✔
603

604
{ #category : #accessing }
UNCOV
605
FamixValue2FASTJavaVisitor >> objectExportStrategy: anObjectExportStrategy [
×
UNCOV
606

×
UNCOV
607
        objectExportStrategy := anObjectExportStrategy
×
UNCOV
608
]
×
609

610
{ #category : #accessing }
611
FamixValue2FASTJavaVisitor >> reflections [
1✔
612

1✔
613
        ^ reflections ifNil: [ reflections := IdentityDictionary new ]
1✔
614
]
1✔
615

616
{ #category : #accessing }
617
FamixValue2FASTJavaVisitor >> statementBlock [
1✔
618

1✔
619
        ^ statementBlock ifNil: [
1✔
620
                  statementBlock := self model newStatementBlock ]
1✔
621
]
1✔
622

623
{ #category : #visiting }
624
FamixValue2FASTJavaVisitor >> visitCollection: collection [
1✔
625
        "Dispatch to type to handle special cases"
1✔
626

1✔
627
        ^ collection type acceptValueVisitor: self forCollection: collection
1✔
628
]
1✔
629

630
{ #category : #visiting }
631
FamixValue2FASTJavaVisitor >> visitCollectionOfRegularType: collection [
1✔
632

1✔
633
        | varName |
1✔
634
        self statementBlock addStatement:
1✔
635
                (self makeVarDeclStatement: collection).
1✔
636
        varName := self varNameDict at: collection.
1✔
637
        collection value do: [ :element |
1✔
638
                self ensureVisited: element value.
1✔
639
                statementBlock addStatement:
1✔
640
                        (self model newExpressionStatement expression:
1✔
641
                                 (model newMethodInvocation
1✔
642
                                          receiver: (model newIdentifier name: varName);
1✔
643
                                          name: 'add';
1✔
644
                                          addArgument: (self makeVariableExpression: element value);
1✔
645
                                          yourself)) ].
1✔
646
        ^ statementBlock
1✔
647
]
1✔
648

649
{ #category : #visiting }
650
FamixValue2FASTJavaVisitor >> visitDictionary: dictionary [
1✔
651

1✔
652
        | varName |
1✔
653
        self statementBlock addStatement:
1✔
654
                (self makeVarDeclStatement: dictionary).
1✔
655
        varName := self varNameDict at: dictionary.
1✔
656
        dictionary value do: [ :association |
1✔
657
                self ensureVisited: association key.
1✔
658
                self ensureVisited: association value.
1✔
659
                statementBlock addStatement:
1✔
660
                        (self model newExpressionStatement expression:
1✔
661
                                 (model newMethodInvocation
1✔
662
                                          receiver: (model newIdentifier name: varName);
1✔
663
                                          name: 'put';
1✔
664
                                          addArgument: (self makeVariableExpression: association key);
1✔
665
                                          addArgument: (self makeVariableExpression: association value);
1✔
666
                                          yourself)) ].
1✔
667
        ^ statementBlock
1✔
668
]
1✔
669

670
{ #category : #visiting }
671
FamixValue2FASTJavaVisitor >> visitEnumValue: enumValue [
1✔
672

1✔
673
        ^ self statementBlock
1✔
674
                  addStatement: (self makeVarDeclStatement: enumValue);
1✔
675
                  yourself
1✔
676
]
1✔
677

678
{ #category : #visiting }
679
FamixValue2FASTJavaVisitor >> visitObject: object [
1✔
680
        "Dispatch to type to handle special cases"
1✔
681

1✔
682
        ^ object type acceptValueVisitor: self forObject: object
1✔
683
]
1✔
684

685
{ #category : #visiting }
686
FamixValue2FASTJavaVisitor >> visitObjectAttribute: attribute [
1✔
687

1✔
688
        attribute attribute ifNil: [ "ignore unknown attributes" ^ self ].
1✔
689
        self ensureVisited: attribute value.
1✔
690
        (attribute object type findSetterOf: attribute attribute)
1✔
691
                ifNotNil: [ :setter | self makeSetterInvocation: setter for: attribute ]
1✔
692
                ifNil: [ self makeReflectionSetterInvocation: attribute ]
1✔
693
]
1✔
694

695
{ #category : #visiting }
696
FamixValue2FASTJavaVisitor >> visitObjectOfRegularType: object [
1✔
697
        "Dispatched here from #visitObject: if the object has a regular creation schema:
1✔
698
        use constructor, then setup each attribute and use setter or reflection."
1✔
699

1✔
700
        (self findStaticAttributeMatching: object)
1✔
701
                ifNotNil: [ :attribute |
1✔
702
                        self makeVarDeclStatement: object usingStaticAttribute: attribute ]
1✔
703
                ifNil: [ self objectExportStrategy export: object on: self ].
1✔
704
        ^ statementBlock
1✔
705
]
1✔
706

707
{ #category : #visiting }
UNCOV
708
FamixValue2FASTJavaVisitor >> visitObjectStub: object [
×
UNCOV
709
        "Previously tried to recreate stubs by deserializing their JSON representation, but getting a correct JSON string is a challenge."
×
UNCOV
710

×
UNCOV
711
        self shouldBeImplemented
×
UNCOV
712
]
×
713

714
{ #category : #visiting }
715
FamixValue2FASTJavaVisitor >> visitPrimitive: primitive [
1✔
716

1✔
717
        ^ self statementBlock
1✔
718
                  addStatement: (self makeVarDeclStatement: primitive);
1✔
719
                  yourself
1✔
720
]
1✔
721

722
{ #category : #visiting }
723
FamixValue2FASTJavaVisitor >> visitValueOfUnknownType: value [
1✔
724

1✔
725
        ^ self statementBlock
1✔
726
                  addStatement: (self makeVarDeclStatement: value);
1✔
727
                  yourself
1✔
728
]
1✔
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