mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
NEW - bug 251856: [Core] NodeContentAdapter does not work
https://bugs.eclipse.org/bugs/show_bug.cgi?id=251856
This commit is contained in:
parent
7b671a9152
commit
191481e84c
3 changed files with 256 additions and 10 deletions
|
@ -37,7 +37,8 @@ public class NodeContentAdapter extends EContentAdapter {
|
|||
}
|
||||
else {
|
||||
AbstractNode predecessor = parent.getChildren().get(position - 1);
|
||||
updateNodeInfo(child, new NodeInfo((predecessor.getOffset() + predecessor.getLength()), predecessor.endLine()));
|
||||
updateNodeInfo(child, new NodeInfo((predecessor.getOffset() + predecessor.getLength()),
|
||||
predecessor.endLine()));
|
||||
}
|
||||
break;
|
||||
case Notification.REMOVE:
|
||||
|
@ -63,6 +64,7 @@ public class NodeContentAdapter extends EContentAdapter {
|
|||
|
||||
@Override
|
||||
protected void setTarget(EObject target) {
|
||||
super.setTarget(target);
|
||||
if (target instanceof AbstractNode) {
|
||||
AbstractNode targetNode = (AbstractNode) target;
|
||||
CompositeNode parent = targetNode.getParent();
|
||||
|
@ -74,7 +76,8 @@ public class NodeContentAdapter extends EContentAdapter {
|
|||
}
|
||||
else {
|
||||
AbstractNode predecessor = siblings.get(index - 1);
|
||||
updateNodeInfo(targetNode, new NodeInfo((predecessor.getOffset() + predecessor.getLength()), predecessor.endLine()));
|
||||
updateNodeInfo(targetNode, new NodeInfo((predecessor.getOffset() + predecessor.getLength()),
|
||||
predecessor.endLine()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -86,21 +89,30 @@ public class NodeContentAdapter extends EContentAdapter {
|
|||
static class NodeInfo {
|
||||
int offset;
|
||||
int line;
|
||||
|
||||
|
||||
public NodeInfo(int offset, int line) {
|
||||
this.offset = offset;
|
||||
this.line = line;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set <code>info</code> on <code>node</code> and then descent into the
|
||||
* contents of node updating length and offset.
|
||||
*
|
||||
* @param node
|
||||
* @param info
|
||||
* @return
|
||||
*/
|
||||
protected NodeInfo updateNodeInfoInContents(AbstractNode node, NodeInfo info) {
|
||||
node.setOffset(info.offset);
|
||||
node.setLine(info.line);
|
||||
if (node instanceof LeafNode) {
|
||||
node.setLength(((LeafNode)node).getText().length());
|
||||
node.setLength(((LeafNode) node).getText().length());
|
||||
info.offset += node.getLength();
|
||||
info.line = node.endLine();
|
||||
} else if (node instanceof CompositeNode) {
|
||||
}
|
||||
else if (node instanceof CompositeNode) {
|
||||
int length = 0;
|
||||
for (AbstractNode child : ((CompositeNode) node).getChildren()) {
|
||||
info = updateNodeInfoInContents(child, info);
|
||||
|
@ -111,16 +123,46 @@ public class NodeContentAdapter extends EContentAdapter {
|
|||
return info;
|
||||
}
|
||||
|
||||
protected AbstractNode updateNodeInfo(AbstractNode node, NodeInfo info) {
|
||||
protected void updateNodeInfo(AbstractNode node, NodeInfo info) {
|
||||
updateNodeInfoInContents(node, info);
|
||||
updateFollowingNodes(node, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a node in a tree changes its size, the offset of all following nodes
|
||||
* (successors, their contents, successors of the parent and their content)
|
||||
* must be updated.
|
||||
*
|
||||
* @param node
|
||||
* @param info
|
||||
*/
|
||||
protected void updateFollowingNodes(AbstractNode node, NodeInfo info) {
|
||||
CompositeNode parent = node.getParent();
|
||||
if (parent != null) {
|
||||
EList<AbstractNode> siblings = parent.getChildren();
|
||||
int index = siblings.indexOf(node);
|
||||
for (int i = index + 1; i < siblings.size(); ++i) {
|
||||
info = updateNodeInfoInContents(siblings.get(i), info);
|
||||
int parentLength=0;
|
||||
for (int i = 0; i < siblings.size(); ++i) {
|
||||
AbstractNode sibling = siblings.get(i);
|
||||
parentLength += sibling.getLength();
|
||||
if(i > index) {
|
||||
info = updateNodeInfoInContents(sibling, info);
|
||||
}
|
||||
}
|
||||
parent.setLength(parentLength);
|
||||
updateFollowingNodes(parent, info);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(java.
|
||||
* lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean isAdapterForType(Object type) {
|
||||
return type == NodeContentAdapter.class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.EList;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
|
||||
|
@ -137,5 +138,33 @@ public class NodeUtil {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CompositeNode findLastCompositeGrandChild(CompositeNode parentNode) {
|
||||
EList<AbstractNode> children = parentNode.getChildren();
|
||||
for(int i=children.size()-1; i>=0; --i) {
|
||||
AbstractNode child = children.get(i);
|
||||
if (child instanceof CompositeNode) {
|
||||
return findLastCompositeGrandChild((CompositeNode) child);
|
||||
}
|
||||
}
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
public static void checkOffsetConsistency(CompositeNode rootNode) {
|
||||
int currentOffset = rootNode.getOffset();
|
||||
for(AbstractNode child:rootNode.getChildren()) {
|
||||
if(child.getOffset() != currentOffset) {
|
||||
throw new IllegalStateException("Invalid offset: Should be " + currentOffset + " but is " + child.getOffset() + "\n" + child.serialize());
|
||||
}
|
||||
if(child instanceof CompositeNode) {
|
||||
checkOffsetConsistency((CompositeNode) child);
|
||||
}
|
||||
int serializedLength = child.serialize().length();
|
||||
if(child.getLength() != serializedLength) {
|
||||
throw new IllegalStateException("Invalid length: Should be " + serializedLength + " but is " + child.getLength() + "\n" + child.serialize());
|
||||
}
|
||||
currentOffset += serializedLength;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.parsetree;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* @author Jan Köhnlein - Initial contribution and API
|
||||
*/
|
||||
public class NodeContentAdapterTest extends TestCase {
|
||||
|
||||
private static final String TEXT0 = "Tests\n";
|
||||
private static final String TEXT1 = "are\n";
|
||||
private static final String TEXT2 = "so\n";
|
||||
private static final String TEXT3 = "great\n";
|
||||
private static final String TEXT4 = "not\n";
|
||||
|
||||
private CompositeNode root;
|
||||
private CompositeNode comp0;
|
||||
private CompositeNode comp1;
|
||||
private LeafNode leaf0;
|
||||
private LeafNode leaf1;
|
||||
private LeafNode leaf2;
|
||||
private LeafNode leaf3;
|
||||
private NodeContentAdapter contentAdapter;
|
||||
|
||||
/**
|
||||
* root +- leaf0
|
||||
* +- comp0 +- leaf1
|
||||
* +- comp1 +- leaf2
|
||||
* +- leaf3
|
||||
*/
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
root = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
contentAdapter = new NodeContentAdapter();
|
||||
}
|
||||
|
||||
private void createTree(CompositeNode root) {
|
||||
comp0 = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
comp1 = ParsetreeFactory.eINSTANCE.createCompositeNode();
|
||||
leaf0 = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
leaf1 = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
leaf2 = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
leaf3 = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
|
||||
leaf0.setText(TEXT0);
|
||||
leaf1.setText(TEXT1);
|
||||
leaf2.setText(TEXT2);
|
||||
leaf3.setText(TEXT3);
|
||||
|
||||
root.getChildren().add(leaf0);
|
||||
root.getChildren().add(comp0);
|
||||
comp0.getChildren().add(leaf1);
|
||||
root.getChildren().add(comp1);
|
||||
comp1.getChildren().add(leaf2);
|
||||
root.getChildren().add(leaf3);
|
||||
}
|
||||
|
||||
public void testAdaptContainment() throws Exception {
|
||||
createTree(root);
|
||||
root.eAdapters().add(contentAdapter);
|
||||
assertInitialSetting();
|
||||
}
|
||||
|
||||
public void testAdaptOnAdd() throws Exception {
|
||||
root.eAdapters().add(contentAdapter);
|
||||
createTree(root);
|
||||
assertInitialSetting();
|
||||
}
|
||||
|
||||
private void assertInitialSetting() {
|
||||
assertTrue(comp0.eAdapters().contains(contentAdapter));
|
||||
assertTrue(comp1.eAdapters().contains(contentAdapter));
|
||||
assertTrue(leaf0.eAdapters().contains(contentAdapter));
|
||||
assertTrue(leaf1.eAdapters().contains(contentAdapter));
|
||||
assertTrue(leaf2.eAdapters().contains(contentAdapter));
|
||||
assertTrue(leaf3.eAdapters().contains(contentAdapter));
|
||||
|
||||
assertEquals(0, root.getOffset());
|
||||
assertEquals(0, leaf0.getOffset());
|
||||
assertEquals(TEXT0.length(), comp0.getOffset());
|
||||
assertEquals(TEXT0.length(), leaf1.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length(), comp1.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length(), leaf2.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT2.length(), leaf3.getOffset());
|
||||
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT2.length() + TEXT3.length(), root.getLength());
|
||||
assertEquals(TEXT0.length(), leaf0.getLength());
|
||||
assertEquals(TEXT1.length(), comp0.getLength());
|
||||
assertEquals(TEXT1.length(), leaf1.getLength());
|
||||
assertEquals(TEXT2.length(), comp1.getLength());
|
||||
assertEquals(TEXT2.length(), leaf2.getLength());
|
||||
assertEquals(TEXT3.length(), leaf3.getLength());
|
||||
|
||||
assertEquals(1, root.getLine());
|
||||
assertEquals(1, leaf0.getLine());
|
||||
assertEquals(2, comp0.getLine());
|
||||
assertEquals(2, leaf1.getLine());
|
||||
assertEquals(3, comp1.getLine());
|
||||
assertEquals(3, leaf2.getLine());
|
||||
assertEquals(4, leaf3.getLine());
|
||||
}
|
||||
|
||||
|
||||
public void testRemove() throws Exception {
|
||||
createTree(root);
|
||||
root.eAdapters().add(contentAdapter);
|
||||
|
||||
comp0.getChildren().remove(leaf1);
|
||||
|
||||
assertEquals(0, root.getOffset());
|
||||
assertEquals(0, leaf0.getOffset());
|
||||
assertEquals(TEXT0.length(), comp0.getOffset());
|
||||
assertEquals(TEXT0.length(), comp1.getOffset());
|
||||
assertEquals(TEXT0.length(), leaf2.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT2.length(), leaf3.getOffset());
|
||||
|
||||
assertEquals(TEXT0.length() + TEXT2.length() + TEXT3.length(), root.getLength());
|
||||
assertEquals(TEXT0.length(), leaf0.getLength());
|
||||
assertEquals(0, comp0.getLength());
|
||||
assertEquals(TEXT2.length(), comp1.getLength());
|
||||
assertEquals(TEXT2.length(), leaf2.getLength());
|
||||
assertEquals(TEXT3.length(), leaf3.getLength());
|
||||
|
||||
assertEquals(1, root.getLine());
|
||||
assertEquals(1, leaf0.getLine());
|
||||
assertEquals(2, comp0.getLine());
|
||||
assertEquals(2, comp1.getLine());
|
||||
assertEquals(2, leaf2.getLine());
|
||||
assertEquals(3, leaf3.getLine());
|
||||
}
|
||||
|
||||
public void testAdd() throws Exception {
|
||||
createTree(root);
|
||||
root.eAdapters().add(contentAdapter);
|
||||
|
||||
LeafNode leaf4 = ParsetreeFactory.eINSTANCE.createLeafNode();
|
||||
leaf4.setText(TEXT4);
|
||||
|
||||
comp0.getChildren().add(0, leaf4);
|
||||
|
||||
assertEquals(0, root.getOffset());
|
||||
assertEquals(0, leaf0.getOffset());
|
||||
assertEquals(TEXT0.length(), comp0.getOffset());
|
||||
assertEquals(TEXT0.length(), leaf4.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT4.length(), leaf1.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT4.length(), comp1.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT4.length(), leaf2.getOffset());
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT2.length() + TEXT4.length(), leaf3.getOffset());
|
||||
|
||||
assertEquals(TEXT0.length() + TEXT1.length() + TEXT2.length() + TEXT3.length() + TEXT4.length(), root.getLength());
|
||||
assertEquals(TEXT0.length(), leaf0.getLength());
|
||||
assertEquals(TEXT4.length() + TEXT1.length(), comp0.getLength());
|
||||
assertEquals(TEXT4.length(), leaf4.getLength());
|
||||
assertEquals(TEXT1.length(), leaf1.getLength());
|
||||
assertEquals(TEXT2.length(), comp1.getLength());
|
||||
assertEquals(TEXT2.length(), leaf2.getLength());
|
||||
assertEquals(TEXT3.length(), leaf3.getLength());
|
||||
|
||||
assertEquals(1, root.getLine());
|
||||
assertEquals(1, leaf0.getLine());
|
||||
assertEquals(2, comp0.getLine());
|
||||
assertEquals(2, leaf4.getLine());
|
||||
assertEquals(3, leaf1.getLine());
|
||||
assertEquals(4, comp1.getLine());
|
||||
assertEquals(4, leaf2.getLine());
|
||||
assertEquals(5, leaf3.getLine());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue