Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Web Tools Project (WTP) » JSDT multiple modifications with single ASTRewrite
JSDT multiple modifications with single ASTRewrite [message #556741] Thu, 02 September 2010 09:45 Go to next message
Harald Finster is currently offline Harald Finster
Messages: 37
Registered: July 2009
Member
Hello,

are there any problems and/or restrictions on the number/kind
of modifications which may be performed with a single ASTRewrite
when editing JavaScript documents using JSDT?

To be more specific, I have the following problem.

I create an ASTRewrite with the following snippet:

ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(document.get().toCharArray());
JavaScriptUnit unit = (JavaScriptUnit) parser.createAST(null);
ASTRewrite rewrite = ASTRewrite.create(unit.getAST());

then I perform several modifications using the rewrite
(see below for details) and apply the modifications as
follows:

TextEdit edits = rewrite.rewriteAST(document, null);
edits.apply(document);

The following cases work fine with the code below
if applied in isolation

1) replacing a VariableDeclarationFragment (see code below)

2) adding a TextElement to the fragments of the comment (see code below)

However, the modification of the comment (2) is ignored
if I try to combine it with (1). The order does not
seem to make any difference.

This is the test code:

package test;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.wst.jsdt.core.dom.AST;
import org.eclipse.wst.jsdt.core.dom.ASTNode;
import org.eclipse.wst.jsdt.core.dom.ASTParser;
import org.eclipse.wst.jsdt.core.dom.JSdoc;
import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
import org.eclipse.wst.jsdt.core.dom.TagElement;
import org.eclipse.wst.jsdt.core.dom.TextElement;
import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment;
import org.eclipse.wst.jsdt.core.dom.VariableDeclarationStatement;
import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.wst.jsdt.core.dom.rewrite.ListRewrite;

public class TestRewrite {

/**
* @param args
* @throws BadLocationException
* @throws MalformedTreeException
*/
public static void main(String[] args) throws MalformedTreeException,
BadLocationException {

System.out.println("TestRewrite");

Document document = new Document(
"/**\n* @tag1 value1\n*/\nvar x;\nvar y;");

System.out.println("initial document\n" + document.get());

ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(document.get().toCharArray());
JavaScriptUnit unit = (JavaScriptUnit) parser.createAST(null);

System.out.println("initial AST\n" + unit);

ASTRewrite rewrite = ASTRewrite.create(unit.getAST());

// case 1
substituteVariableDeclaration(rewrite, unit);

// case 2
addDocumentFragment(rewrite, unit);


TextEdit edits = rewrite.rewriteAST(document, null);
System.out.println("edits\n" + edits);
edits.apply(document);

System.out.println("modified document\n" + document.get());
}

/**
* substitute the 0th VariableDeclarationFragment of the 0th Statement
* ("var x;") with a new VariableDeclarationFragment ("var newX")
*/
private static void substituteVariableDeclaration(ASTRewrite rewrite,
JavaScriptUnit unit) {

// get the old fragment (var x;)
//
VariableDeclarationStatement stmt = (VariableDeclarationStatement) unit
.statements().get(0);

VariableDeclarationFragment oldFragment = (VariableDeclarationFragment) stmt
.fragments().get(0);

// create a new fragment (var newX)
//
VariableDeclarationFragment newFragment = unit.getAST()
.newVariableDeclarationFragment();

newFragment.setName(unit.getAST().newSimpleName("newX"));

rewrite.replace(oldFragment, newFragment, null);

}



private static void addDocumentFragment(ASTRewrite rewrite,
JavaScriptUnit unit) {

//
// get the 0th comment fragment of the 0th comment
//
JSdoc doc = (JSdoc) unit.getCommentList().get(0);
TagElement tag = (TagElement) doc.tags().get(0);
TextElement fragment = (TextElement) tag.fragments().get(0);

// append new text element
//
ListRewrite listRewrite = rewrite.getListRewrite(tag,
TagElement.FRAGMENTS_PROPERTY);

TextElement text = (TextElement) rewrite.createStringPlaceholder(
"new-fragment", ASTNode.TEXT_ELEMENT);

listRewrite.insertLast(text, null);

}
}


if I use substituteVariableDeclaration(rewrite, unit); only the output is

TestRewrite
initial document
/**
* @tag1 value1
*/
var x;
var y;
initial AST
var x;
var y;

edits
{MultiTextEdit} [26,1] [undefined]
{InsertEdit} [26,0] <<newX
{DeleteEdit} [26,1]
modified document
/**
* @tag1 value1
*/
var newX;
var y;

(correct)

if I use addDocumentFragment(rewrite, unit); only the output is

....
edits
{MultiTextEdit} [18,0] [undefined]
{InsertEdit} [18,0] <<
{InsertEdit} [18,0] <<new-fragment
modified document
/**
* @tag1 value1 new-fragment
*/
var x;
var y;


(correct)


if I use both methods, i.e.
substituteVariableDeclaration(rewrite, unit);
addDocumentFragment(rewrite, unit);

the output is

....
edits
{MultiTextEdit} [26,1] [undefined]
{InsertEdit} [26,0] <<newX
{DeleteEdit} [26,1]
modified document
/**
* @tag1 value1
*/
var newX;
var y;


which is not correct (well, at least not what I would expect),
as the "new-fragment" text is missing.

Note: I also tried to add a VariableDeclarationStatement in
conjunction with the replacement operation and it worked fine.
So, performing multiple edits with a single rewrite does
not seem to be a problem in principle. (?)


Thanks for your feedback in advance!

Kind regards

Harald Finster

P.S. I am using

JavaScript Developer Tools
Version: 1.1.1.v200906091427-77-FGBCcNBC-BeMcEeOm
Build id: 20090616035105
Re: JSDT multiple modifications with single ASTRewrite [message #556924 is a reply to message #556741] Fri, 03 September 2010 03:52 Go to previous messageGo to next message
Harald Finster is currently offline Harald Finster
Messages: 37
Registered: July 2009
Member
Hello,

addditional info:
I tested the same with a target platform based on
Helios, namely

JavaScript Development Tools
Version: 1.2.0.v201005270528-7C78FGDF9JgLWLMBWz-Ose6
Build id: 20100615235519

>
> JavaScript Developer Tools
> Version: 1.1.1.v200906091427-77-FGBCcNBC-BeMcEeOm
> Build id: 20090616035105
>
Re: JSDT multiple modifications with single ASTRewrite [message #556988 is a reply to message #556924] Fri, 03 September 2010 09:40 Go to previous messageGo to next message
Harald Finster is currently offline Harald Finster
Messages: 37
Registered: July 2009
Member
Hello,

further nvestigation of the matter reveals the following:

The problem seems to occur only, if the comment in question
is a child of the modified statement.

The following modification works fine:

original document:
/**
* @tag value
*/
var x;
var y;

modifications:
- add text element "newValue" to jsdoc fragment
- modify 1st VariableDeclarationStatement (var y;)

modified document:
/**
* @tag value newValue
*/
var x;
var newY;


This one does not work (same original document):

modifications:
- add text element "newValue" to jsdoc fragment
- modify 0th VariableDeclarationStatement (var x;)

modified document:
/**
* @tag value (*** nothin happens ***)
*/
var newX;
var y;



I did some debugging in ASTRewriterAnalyser and found some
'suspicious' code in visit(VariableDeclarationStatement node):

doVisitUnchaged seems to make the visitor visit the JSdoc
comments. However this seems to be executed only, if the node
does not have any children changes.
Thus, if "var x;" is modified to "var newX;" the node has
children changes (the VariableDeclarationStatement) and the
child JSdoc comment is not visited.

A quick-and-probably-extremely-dirty hack would be to
call "doVisitUnchangedChildren()" in any case.
(At least this solsves my problem.) However, I suspect, that
this might cause some bad side effects.


Any thoughts?

Greetings Harald










Harald Finster schrieb:
> Hello,
>
> addditional info:
> I tested the same with a target platform based on
> Helios, namely
>
> JavaScript Development Tools
> Version: 1.2.0.v201005270528-7C78FGDF9JgLWLMBWz-Ose6
> Build id: 20100615235519
>
>>
>> JavaScript Developer Tools
>> Version: 1.1.1.v200906091427-77-FGBCcNBC-BeMcEeOm
>> Build id: 20090616035105
>>
Re: (solved/work around) JSDT multiple modifications with single ASTRewrite [message #556995 is a reply to message #556988] Fri, 03 September 2010 10:24 Go to previous message
Harald Finster is currently offline Harald Finster
Messages: 37
Registered: July 2009
Member
Hello,

I found the following workaround:

Create a new MultiTextEdit

Create a new rewrite for each modification of the AST

Add the edits retreived from the rewriter as children to the MultiTextEdit

after all modifications have been done:

Apply the edits 'collected' in the MultiTextEdit to the document.

Harald

P.S.
anyways:
could one of the JSDT gurus please check, if there is a bug in the (JSDT) AST rewrite mechanism?




Harald Finster schrieb:
> Hello,
>
> further nvestigation of the matter reveals the following:
>
> The problem seems to occur only, if the comment in question
> is a child of the modified statement.
>
> The following modification works fine:
>
> original document:
> /**
> * @tag value
> */
> var x;
> var y;
>
> modifications:
> - add text element "newValue" to jsdoc fragment
> - modify 1st VariableDeclarationStatement (var y;)
>
> modified document:
> /**
> * @tag value newValue
> */
> var x;
> var newY;
>
>
> This one does not work (same original document):
>
> modifications:
> - add text element "newValue" to jsdoc fragment
> - modify 0th VariableDeclarationStatement (var x;)
>
> modified document:
> /**
> * @tag value (*** nothin happens ***)
> */
> var newX;
> var y;
>
>
>
> I did some debugging in ASTRewriterAnalyser and found some
> 'suspicious' code in visit(VariableDeclarationStatement node):
>
> doVisitUnchaged seems to make the visitor visit the JSdoc
> comments. However this seems to be executed only, if the node
> does not have any children changes.
> Thus, if "var x;" is modified to "var newX;" the node has
> children changes (the VariableDeclarationStatement) and the
> child JSdoc comment is not visited.
>
> A quick-and-probably-extremely-dirty hack would be to
> call "doVisitUnchangedChildren()" in any case.
> (At least this solsves my problem.) However, I suspect, that
> this might cause some bad side effects.
>
>
> Any thoughts?
>
> Greetings Harald
>
>
>
>
>
>
>
>
>
>
> Harald Finster schrieb:
>> Hello,
>>
>> addditional info:
>> I tested the same with a target platform based on
>> Helios, namely
>>
>> JavaScript Development Tools
>> Version: 1.2.0.v201005270528-7C78FGDF9JgLWLMBWz-Ose6
>> Build id: 20100615235519
>>
>>>
>>> JavaScript Developer Tools
>>> Version: 1.1.1.v200906091427-77-FGBCcNBC-BeMcEeOm
>>> Build id: 20090616035105
>>>
Previous Topic:Adding xsd to XML validator
Next Topic:generate web services programmatically
Goto Forum:
  


Current Time: Fri Aug 29 14:21:29 EDT 2014

Powered by FUDForum. Page generated in 0.03459 seconds