Menu

how to move field to another typeDeclaration

Developers
2011-09-01
2012-10-08
  • Frederik Schmidt

    Hi recoder developers,

    I would like to write a transformation to move a field from one
    typeDeclaration to another. Its no problem to erase a field from one type
    declaration. However, im struggeling to add the field in another
    typeDeclaration. See the code snippet for current attempt below. Based on the
    transformation tutorial i would need a statementBlock to attach the field.
    unfortunately, im not able to retrieve a StatementBlock from the available
    TypeDeclaration to attach the field.

    Maybe someone can give a hint how to solve this issue.

    private void addField(TypeDeclaration targetTypeDeclaration, Field field)
    {
    List<Field> allFields = targetTypeDeclaration.getAllFields();
    allFields.add(field); // certainly this doesnt write back into the definition
    of the typeDeclaration.
    CrossReferenceServiceConfiguration crsc =
    CrossReferenceServiceConfigurationFactory.getInstance();
    ChangeHistory changeHistory = crsc.getChangeHistory();
    ProgramElement pElement = (ProgramElement) field;
    changeHistory.attached(pElement);
    }

    regards
    Frederik

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2011-09-01

    Hi,

    There are two issues:
    1) A "field" is never attached to a StatementBlock, but to a TypeDeclaration.
    Only "local variables" can be attached to statement blocks.
    2) There's an essential difference between a general "Field" and a
    "FieldDeclaration" (this generailizes to other members as well). A "Field"
    can, e.g., also be a "FieldInfo" as retrieved from bytecode; recoder does not
    refactor bytecode. A "FieldDeclaration" is a field that is present in the AST,
    i.e., in the analyzed source code.
    Now, "getAllFields()" also returns a List also including inherited fields.
    What you are looking for is "getFields()", which returns an ASTList. An
    ASTList is part of the AST; changes to it are reflected in the AST.

    What you probably are looking for is this (warning: untested, I leave that to
    you :))
    private void addField(TypeDeclaration targetTypeDeclaration, Field field) {
    ASTList<Field> fields = targetTypeDeclaration.getFields();
    fields.add(targetTypeDeclaration.getProgramFactory().createFieldDeclaration(..
    .);
    // rest as you wrote it...
    }

    You will have to provide proper arguments to createFieldDeclaration(). The
    following constructor should be present (again, I didn't test it as I don't
    have recoder at hand right now):
    pf.createFieldDeclaration(TypeKit.createTypeReference(field.getType()),
    field.getName());

    Let me know if you have any further questions.

    Best regards,
    Tobias

     
  • Frederik Schmidt

    Hi Tobias,

    thanks for your help... Below a code snipped including your hints, which
    enabled me to move a field to a given type declaration. Its certainly not
    perfect, but for now it does the job:-) Thanks again

    cheers
    frederik

    private void addFieldToTypeDeclaration(TypeDeclaration targetTypeDeclaration,
    Field field)
    {
    FieldSpecification fieldSpecification = (FieldSpecification) field;

    ASTList<DeclarationSpecifier> declarationSpecifiers =
    fieldSpecification.getDeclarationSpecifiers();
    JavaProgramFactory factory = targetTypeDeclaration.getFactory();

    FieldDeclaration parent = fieldSpecification.getParent();
    TypeReference typeReference = parent.getTypeReference();

    FieldDeclaration fieldDeclaration = factory.createFieldDeclaration();

    fieldDeclaration.setDeclarationSpecifiers(declarationSpecifiers);
    fieldDeclaration.setFactory(factory);
    fieldDeclaration.setMemberParent(targetTypeDeclaration);
    fieldDeclaration.setTypeReference(typeReference);

    ASTArrayList<FieldSpecification> fieldSpecifications = new
    ASTArrayList<FieldSpecification>();

    fieldSpecification.setParent(fieldDeclaration);
    fieldSpecifications.add(fieldSpecification);
    fieldDeclaration.setFieldSpecifications(fieldSpecifications);

    ASTList<MemberDeclaration> members = targetTypeDeclaration.getMembers();
    members.add(0, fieldDeclaration);

    CrossReferenceServiceConfiguration crsc =
    CrossReferenceServiceConfigurationFactory.getInstance();
    ChangeHistory changeHistory = crsc.getChangeHistory();
    ProgramElement pElement = (ProgramElement) fieldDeclaration;
    changeHistory.attached(fieldSpecification);
    changeHistory.attached(pElement);

    }

     
  • Tobias Gutzmann

    Tobias Gutzmann - 2011-09-12

    Hi,

    If you somehow can guarantee that a FieldDeclaration has only one
    FieldSpecification, it can be done much easier because you can just move/clone
    the FieldDeclaration (examples for a FieldDeclaration with two
    FieldSpecifications: int a, b; -- it makes source code transformations in
    general much more complicated...):
    In this case you can just deepClone() the FieldDeclaration (note: it's
    always better to deepClone() than reusing an AST object, for defensive
    programming reasons...)

    TypeDeclaration from = ...;
    TypeDeclaration to = ...;
    FieldDeclaration fd = ...;
    FieldDeclaration replFd = fd.deepClone();
    int idx = from.getChildPositionCode(fd);
    from.replaceChild(fd, null);
    to.getMemberDeclarations().add(replFD);
    to.makeRoleValid();
    sc.getChangeHistory().detached(fd, idx);
    sc.getChangeHistory().attached(replFD);

    (Again, I haven't actually executed the code above...)

    Best regards,
    Tobias

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.