class SupportChainOverridingProcessor extends AbstractClassProcessor {
val String extensionClassNameSuffix = 'Extension'
override doRegisterGlobals(ClassDeclaration annotatedClass, RegisterGlobalsContext context) {
context.registerClass(annotatedClass.extensionClassName)
}
override doTransform(MutableClassDeclaration annotatedClass, extension TransformationContext context) {
if (validate(annotatedClass, context)) {
val extensionClass = createExtensionClass(annotatedClass, context)
transformAnnotatedClass(annotatedClass, extensionClass, context)
}
}
private def getExtensionClassName(ClassDeclaration annotatedClass) {
annotatedClass.qualifiedName + extensionClassNameSuffix
}
private def boolean validate(MutableClassDeclaration annotatedClass, extension TransformationContext context) {
// Check if annotated class does extend another class
if (annotatedClass.extendedClass?.name != 'java.lang.Object') {
annotatedClass.addError('Annotated class must not extend a class')
return false
}
true
}
private def createExtensionClass(MutableClassDeclaration annotatedClass, extension TransformationContext context) {
val extensionClass = findClass(annotatedClass.extensionClassName)
// Extend from annotated class
extensionClass.extendedClass = annotatedClass.newTypeReference
// Add default constructor which initializes the chaining with null
extensionClass.addConstructor[
body = ['''super(null);''']
]
// Copy all annotations from annotated class (excluding our own annotation)
annotatedClass.annotations.filter[
annotationTypeDeclaration.simpleName != 'org.sculptor.generator.chain.SupportChainOverriding'].forEach[
extensionClass.addAnnotation(annotationTypeDeclaration)]
// Copy all fields from annotated class
annotatedClass.declaredFields.forEach[sourceField |
extensionClass.addField(sourceField.simpleName) [targetField |
targetField.final = sourceField.final
targetField.static = sourceField.static
targetField.transient = sourceField.transient
targetField.volatile = sourceField.volatile
targetField.initializer = sourceField.initializer
targetField.type = sourceField.type
targetField.docComment = sourceField.docComment
targetField.visibility = sourceField.visibility
sourceField.annotations.forEach[targetField.addAnnotation(annotationTypeDeclaration)]
]
]
// Copy all methods from annotated class
annotatedClass.declaredMethods.forEach[sourceMethod |
extensionClass.addMethod(sourceMethod.simpleName) [targetMethod |
targetMethod.returnType = sourceMethod.returnType
targetMethod.static = sourceMethod.static
targetMethod.final = sourceMethod.final
targetMethod.strictFloatingPoint = sourceMethod.strictFloatingPoint
targetMethod.native = sourceMethod.native
targetMethod.abstract = sourceMethod.abstract
targetMethod.synchronized = sourceMethod.synchronized
targetMethod.^default = sourceMethod.^default
targetMethod.varArgs = sourceMethod.varArgs
targetMethod.body = sourceMethod.body // FIXME How to relocate the field type references to the extension class?
targetMethod.exceptions = sourceMethod.exceptions
sourceMethod.parameters.forEach[targetMethod.addParameter(simpleName, type)]
// FIXME How to copy type parameters?
targetMethod.docComment = sourceMethod.docComment
targetMethod.visibility = sourceMethod.visibility
sourceMethod.annotations.forEach [targetMethod.addAnnotation(annotationTypeDeclaration)]
]
]
extensionClass
}
private def transformAnnotatedClass(MutableClassDeclaration annotatedClass, MutableClassDeclaration extensionClass,
extension TransformationContext context) {
// Extend from chain link class referencing the generated extension class
val extensionClassRef = extensionClass.newTypeReference
annotatedClass.extendedClass = typeof(ChainLink).newTypeReference(extensionClassRef)
// add constructor for chaining
annotatedClass.addConstructor [
addParameter("next", extensionClassRef)
body = ['''super(next);''']
]
// remove all fields and methods
annotatedClass.declaredFields.forEach[remove]
annotatedClass.declaredMethods.forEach[remove]
// add methods delegating to the given extension class' public non-final methods
extensionClass.declaredMethods.filter [
visibility == Visibility::PUBLIC && !final && !static
].forEach [ extensionMethod |
annotatedClass.addMethod(extensionMethod.simpleName) [ delegateMethod |
delegateMethod.returnType = extensionMethod.returnType
delegateMethod.^default = extensionMethod.^default
delegateMethod.varArgs = extensionMethod.varArgs
delegateMethod.exceptions = extensionMethod.exceptions
extensionMethod.parameters.forEach[delegateMethod.addParameter(simpleName, type)]
delegateMethod.docComment = extensionMethod.docComment
delegateMethod.body = [
'''
return getNext().«extensionMethod.simpleName»(«FOR p : extensionMethod.parameters SEPARATOR ", "»«p.simpleName»«ENDFOR»);
'''
]
]
]
}
}
What exactly do you mean by "all field type references are pointing to the type of the original class"?
package acme
@org.sculptor.generator.chain.CopyingSupportChainOverriding
class Foo {
var String field = 'foo'
def method() {
field = 'bar'
}
}
File 1 : acme/Foo.javapackage acme;import acme.FooExtension;import org.sculptor.generator.chain.CopyingSupportChainOverriding;import org.sculptor.generator.util.ChainLink;@CopyingSupportChainOverriding@SuppressWarnings("all")public class Foo extends ChainLink<FooExtension> {private String field;public Foo(final FooExtension next) {super(next);}public String method() {return getNext().method();}}File 2 : acme/FooExtension.javapackage acme;import acme.Foo;import org.sculptor.generator.chain.CopyingSupportChainOverriding;@CopyingSupportChainOverriding@SuppressWarnings("all")public class FooExtension extends Foo {public FooExtension() {super(null);}private String field = "foo";public String method() {String _field = super.field = "bar";return _field;}}
File 1 : acme/Foo.javapackage acme;import acme.FooExtension;import org.sculptor.generator.chain.CopyingSupportChainOverriding;import org.sculptor.generator.util.ChainLink;@CopyingSupportChainOverriding@SuppressWarnings("all")public class Foo extends ChainLink<FooExtension> {private String field;public Foo(final FooExtension next) {super(next);}public String method() {return getNext().method();}}File 2 : acme/FooExtension.javapackage acme;import acme.Foo;import org.sculptor.generator.chain.CopyingSupportChainOverriding;@CopyingSupportChainOverriding@SuppressWarnings("all")public class FooExtension {private String field = "foo";public String method() {Foo _Foo = Foo;String _field = _Foo.field = "bar";return _field;}}
--
You received this message because you are subscribed to the Google Groups "Xtend Programming Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to xtend-lang+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
Could you please open a bugzilla and attach the info below?
This is most likely caused by the return type of operations to be resolved before the names / expressions are properly set. E.g. after method.getReturnType the method's body is linked and therefore the references still point to the old fields. Can you try with a sample file that does not contain inferred return types?