Bug 93208

Summary: [dom] CompilationUnit.rewrite throws AssertionFailedException with legal AST (bug in recoding ast modifications)
Product: [Eclipse Project] JDT Reporter: Rodrigo Kumpera <kumpera>
Component: CoreAssignee: David Audel <david_audel>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3    
Version: 3.0.2   
Target Milestone: 3.1 RC2   
Hardware: PC   
OS: Windows NT   
Whiteboard:
Attachments:
Description Flags
JUnit testcase for the bug none

Description Rodrigo Kumpera CLA 2005-04-28 21:25:41 EDT
While recording AST modifications and copySubtree is performed on a node from 
the same AST, eg: ASTNode x = ast.newXXX ... y = ASTNode.copySubtree(ast, x), 
when the edit is requested it fails to get the source from the original node 
with an Assertion exception.

I'm not sure if it's my fault, but ASTNode.copySubtree javadoc implies that 
this is a legal operation.

I get the following stack trace when running the attached unit test (irrelevant 
traces removed):

org.eclipse.jface.text.Assert$AssertionFailedException: Assertion failed: 
	at org.eclipse.jface.text.Assert.isTrue(Assert.java:177)
	at org.eclipse.jface.text.Assert.isTrue(Assert.java:162)
	at org.eclipse.text.edits.TextEdit.<init>(TextEdit.java:149)
	at org.eclipse.text.edits.CopySourceEdit.<init>(CopySourceEdit.java:96)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.getCopySourceEdit
(ASTRewriteAnalyzer.java:128)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doTextInsert
(ASTRewriteAnalyzer.java:984)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter.rewrit
eList(ASTRewriteAnalyzer.java:461)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.rewriteParagraphLis
t(ASTRewriteAnalyzer.java:837)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit
(ASTRewriteAnalyzer.java:1263)
	at org.eclipse.jdt.core.dom.TypeDeclaration.accept0
(TypeDeclaration.java:469)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2450)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisit
(ASTRewriteAnalyzer.java:249)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitList
(ASTRewriteAnalyzer.java:280)
	at 
org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitUnchangedChi
ldren(ASTRewriteAnalyzer.java:298)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit
(ASTRewriteAnalyzer.java:1151)
	at org.eclipse.jdt.core.dom.CompilationUnit.accept0
(CompilationUnit.java:287)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2450)
	at org.eclipse.jdt.core.dom.InternalASTRewrite.rewriteAST
(InternalASTRewrite.java:71)
	at org.eclipse.jdt.core.dom.AST.rewrite(AST.java:2642)
	at org.eclipse.jdt.core.dom.CompilationUnit.rewrite
(CompilationUnit.java:853)
	at jdt.tests.AstRewriteBug.testAstRewriteBug(AstRewriteBug.java:60)
Comment 1 Rodrigo Kumpera CLA 2005-04-28 21:27:33 EDT
Created attachment 20487 [details]
JUnit testcase for the bug
Comment 2 Rodrigo Kumpera CLA 2005-05-02 15:46:46 EDT
I've found a workaround for this bug. Instead of copying the subtree, make the 
node orfan and use it. This might even save some bits of memory since 
copySubTree does not perform COW.

This method does the kludge:

    public static void killParent(ASTNode node) {
        StructuralPropertyDescriptor locationInParent = node
                .getLocationInParent();
        if (!locationInParent.isChildListProperty())
            node.getParent().setStructuralProperty(locationInParent, node.getAST
().newNullLiteral());
        else {
            List list = (List) node.getParent().getStructuralProperty(
                    locationInParent);
            list.remove(node);
        }
    }
Comment 3 Olivier Thomann CLA 2005-06-07 11:08:49 EDT
Martin, could you please check if this occurs in HEAD?
Comment 4 Martin Aeschlimann CLA 2005-06-07 11:28:33 EDT
Bug is in the modifying ast rewrite: A close on a new (non-original) node should
not create a copy event. New end original nodes can be distinguised with the
'ASTNode.ORIGINAL' flag.

Moving to Daniel
Comment 5 Philipe Mulet CLA 2005-06-09 09:54:52 EDT
+1 for RC2
Comment 6 David Audel CLA 2005-06-09 09:59:27 EDT
Fixed and test added
  ASTRewritingModifyingCopyTest#test0007()

Replaced

void postCloneNodeEvent(ASTNode node, ASTNode clone) {
	this.clonedNodes.put(clone, node);
	this.cloneDepth--;
}

by

void postCloneNodeEvent(ASTNode node, ASTNode clone) {
	if(node.ast == root.ast && clone.ast == root.ast) {
		if((node.getFlags() & ASTNode.ORIGINAL) != 0) {
			this.clonedNodes.put(clone, node);
		} else {
			// node can be a cloned node
			Object original = this.clonedNodes.get(node);
			if(original != null) {
				this.clonedNodes.put(clone, original);
			}
		}
	}
	this.cloneDepth--;
}
Comment 7 Olivier Thomann CLA 2005-06-09 10:51:27 EDT
Verified in N20050609-0010 + JDT/Core HEAD.

Verified that the attached Junit test passed.
Result in System.out is:
package test; public class Test {

	void foo(){this.x;} }
Comment 8 Olivier Thomann CLA 2005-06-10 12:10:48 EDT
Verified in I20050610-0010.