8
8
import java
9
9
10
10
/** A type that should be in the generated code. */
11
- abstract /* private*/ class GeneratedType extends RefType {
11
+ abstract private class GeneratedType extends RefType {
12
12
GeneratedType ( ) {
13
13
(
14
14
this instanceof Interface
@@ -23,9 +23,9 @@ abstract /*private*/ class GeneratedType extends RefType {
23
23
private string stubKeyword ( ) {
24
24
this instanceof Interface and result = "interface"
25
25
or
26
- this instanceof Class and result = "class"
27
- // or
28
- // this instanceof Enum and result = "enum"
26
+ this instanceof Class and result = "class" and not this instanceof EnumType
27
+ or
28
+ this instanceof EnumType and result = "enum"
29
29
}
30
30
31
31
private string stubAbstractModifier ( ) {
@@ -51,6 +51,7 @@ abstract /*private*/ class GeneratedType extends RefType {
51
51
private RefType getAnInterestingBaseType ( ) {
52
52
result = this .getASupertype ( ) and
53
53
not result instanceof TypeObject and
54
+ not this instanceof EnumType and
54
55
result .getSourceDeclaration ( ) != this
55
56
}
56
57
@@ -78,7 +79,9 @@ abstract /*private*/ class GeneratedType extends RefType {
78
79
79
80
language [ monotonicAggregates]
80
81
private string stubMembers ( ) {
81
- result = concat ( Member m | m = this .getAGeneratedMember ( ) | stubMember ( m ) )
82
+ result =
83
+ stubEnumConstants ( this ) + stubFakeConstructor ( this ) +
84
+ concat ( Member m | m = this .getAGeneratedMember ( ) | stubMember ( m ) )
82
85
}
83
86
84
87
private Member getAGeneratedMember ( ) {
@@ -175,7 +178,7 @@ private string stubAccessibility(Member m) {
175
178
}
176
179
177
180
private string stubModifiers ( Member m ) {
178
- result = stubAccessibility ( m ) + stubStaticOrFinal ( m ) + stubAbstract ( m )
181
+ result = stubAccessibility ( m ) + stubStaticOrFinal ( m ) + stubAbstractOrDefault ( m )
179
182
}
180
183
181
184
private string stubStaticOrFinal ( Member m ) {
@@ -187,9 +190,9 @@ private string stubStaticOrFinal(Member m) {
187
190
else result = ""
188
191
}
189
192
190
- private string stubAbstract ( Member m ) {
193
+ private string stubAbstractOrDefault ( Member m ) {
191
194
if m .getDeclaringType ( ) instanceof Interface
192
- then result = ""
195
+ then if m . isDefault ( ) then result = "default " else result = ""
193
196
else
194
197
if m .isAbstract ( )
195
198
then result = "abstract "
@@ -261,7 +264,7 @@ private string stubGenericMethodParams(Method m) {
261
264
}
262
265
263
266
private string stubImplementation ( Callable c ) {
264
- if c .isAbstract ( ) or c . getDeclaringType ( ) instanceof Interface
267
+ if c .isAbstract ( )
265
268
then result = ";"
266
269
else
267
270
if c instanceof Constructor or c .getReturnType ( ) instanceof VoidType
@@ -305,50 +308,109 @@ private string stubParameter(Parameter p) {
305
308
)
306
309
}
307
310
308
- private string stubMember ( Member m ) {
309
- exists ( Method c | m = c |
310
- result =
311
- " " + stubModifiers ( c ) + stubGenericMethodParams ( c ) + stubTypeName ( c .getReturnType ( ) ) + " "
312
- + c .getName ( ) + "(" + stubParameters ( c ) + ")" + stubImplementation ( c ) + "\n"
313
- )
311
+ private string stubEnumConstants ( RefType t ) {
312
+ if t instanceof EnumType
313
+ then
314
+ exists ( EnumType et | et = t |
315
+ result =
316
+ " " + concat ( EnumConstant c | c = et .getAnEnumConstant ( ) | c .getName ( ) , ", " ) + ";\n"
317
+ )
318
+ else result = ""
319
+ }
320
+
321
+ // Holds if the member is to be excluded from stubMember
322
+ private predicate excludedMember ( Member m ) {
323
+ m instanceof EnumConstant
314
324
or
315
- exists ( Constructor c | m = c |
316
- result =
317
- " " + stubModifiers ( m ) + c . getName ( ) + "(" + stubParameters ( c ) + ")" +
318
- stubImplementation ( c ) + "\n"
325
+ exists ( Method c | m = c |
326
+ c . getDeclaringType ( ) instanceof EnumType and
327
+ m . hasName ( [ "values" , "valueOf" ] ) and
328
+ m . isStatic ( )
319
329
)
320
- or
321
- exists ( Field f , string impl | f = m |
322
- /* and not f instanceof EnumConstant */
323
- /*if f.isConst() then impl = " = throw null" else*/ impl = "" and
324
- result =
325
- " " + stubModifiers ( m ) + stubTypeName ( f .getType ( ) ) + " " + f .getName ( ) + impl + ";\n"
330
+ }
331
+
332
+ private string stubMember ( Member m ) {
333
+ if excludedMember ( m )
334
+ then result = ""
335
+ else (
336
+ exists ( Method c | m = c |
337
+ result =
338
+ " " + stubModifiers ( c ) + stubGenericMethodParams ( c ) + stubTypeName ( c .getReturnType ( ) ) +
339
+ " " + c .getName ( ) + "(" + stubParameters ( c ) + ")" + stubImplementation ( c ) + "\n"
340
+ )
341
+ or
342
+ exists ( Constructor c | m = c |
343
+ result =
344
+ " " + stubModifiers ( m ) + c .getName ( ) + "(" + stubParameters ( c ) + ")" +
345
+ stubImplementation ( c ) + "\n"
346
+ )
347
+ or
348
+ exists ( Field f | f = m |
349
+ result =
350
+ " " + stubModifiers ( m ) + stubTypeName ( f .getType ( ) ) + " " + f .getName ( ) + " = " +
351
+ stubDefaultValue ( f .getType ( ) ) + ";\n"
352
+ )
353
+ or
354
+ exists ( NestedType nt | nt = m | result = indent ( nt .( GeneratedType ) .getStub ( ) ) )
326
355
)
327
- or
328
- exists ( NestedType nt | nt = m | result = indent ( nt .( GeneratedType ) .getStub ( ) ) )
329
356
}
330
357
331
358
bindingset [ s]
332
359
private string indent ( string s ) { result = " " + s .replaceAll ( "\n" , "\n " ) + "\n" }
333
360
334
- private TopLevelType getTopLevel ( RefType t ) {
335
- result = t or
336
- result = getTopLevel ( t .( NestedType ) .getEnclosingType ( ) )
361
+ // If a class's superclass doesn't have a no-arg constructor, then it won't compile when its constructor's bodies are stubbed
362
+ // So we synthesise no-arg constructors for each generated type that doesn't have one.
363
+ private string stubFakeConstructor ( RefType t ) {
364
+ if not t instanceof Class
365
+ then result = ""
366
+ else
367
+ exists ( string mod |
368
+ if t instanceof EnumType then mod = " private " else mod = " protected "
369
+ |
370
+ if hasNoArgConstructor ( t ) then result = "" else result = mod + t .getName ( ) + "() {}\n"
371
+ )
372
+ }
373
+
374
+ private predicate hasNoArgConstructor ( Class t ) {
375
+ exists ( Constructor c | c .getDeclaringType ( ) = t |
376
+ c .getNumberOfParameters ( ) = 0 and
377
+ not c .isPrivate ( )
378
+ )
379
+ }
380
+
381
+ private RefType getAReferencedType ( RefType t ) {
382
+ result = t .( GeneratedType ) .getAGeneratedType ( )
383
+ or
384
+ result =
385
+ getAReferencedType ( any ( NestedType nt |
386
+ nt .getEnclosingType ( ) .getSourceDeclaration ( ) = t .getSourceDeclaration ( )
387
+ ) )
388
+ or
389
+ exists ( RefType t1 | t1 = getAReferencedType ( t ) |
390
+ result = t1 .( NestedType ) .getEnclosingType ( )
391
+ or
392
+ result = t1 .getSourceDeclaration ( )
393
+ or
394
+ result = t1 .( ParameterizedType ) .getATypeArgument ( )
395
+ or
396
+ result = t1 .( Array ) .getElementType ( )
397
+ )
337
398
}
338
399
400
+ /** A top level type whose file should be stubbed */
339
401
class GeneratedTopLevel extends TopLevelType {
340
402
GeneratedTopLevel ( ) {
341
403
this = this .getSourceDeclaration ( ) and
342
404
this instanceof GeneratedType
343
405
}
344
406
345
- RefType getAReferencedType ( ) {
346
- exists ( GeneratedType t | this = getTopLevel ( t ) | result = getTopLevel ( t . getAGeneratedType ( ) ) )
407
+ private TopLevelType getAnImportedType ( ) {
408
+ result = getAReferencedType ( this ) . getSourceDeclaration ( )
347
409
}
348
410
349
411
private string stubAnImport ( ) {
350
412
exists ( RefType t , string pkg , string name |
351
- t = getAReferencedType ( ) . getSourceDeclaration ( ) and
413
+ t = getAnImportedType ( ) and
352
414
( t instanceof Class or t instanceof Interface ) and
353
415
t .hasQualifiedName ( pkg , name ) and
354
416
t != this and
@@ -371,6 +433,7 @@ class GeneratedTopLevel extends TopLevelType {
371
433
"// Generated automatically from " + this .getQualifiedName ( ) + " for testing purposes\n\n"
372
434
}
373
435
436
+ /** Creates a full stub for the file containing this type. */
374
437
string stubFile ( ) {
375
438
result = stubComment ( ) + stubPackage ( ) + stubImports ( ) + this .( GeneratedType ) .getStub ( ) + "\n"
376
439
}
0 commit comments