Copyright (c) 2004, 2013 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2004, 2013 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.jdt.core.dom.rewrite; import java.util.Collections; import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore; import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore; import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; import org.eclipse.text.edits.TextEditGroup;
For describing manipulations to a child list property of an AST node.

This class is not intended to be subclassed.

See Also:
  • getListRewrite.getListRewrite(ASTNode, ChildListPropertyDescriptor)
Since:3.0
/** * For describing manipulations to a child list property of an AST node. * <p> * This class is not intended to be subclassed. * </p> * @see ASTRewrite#getListRewrite(ASTNode, ChildListPropertyDescriptor) * @since 3.0 */
@SuppressWarnings({"rawtypes", "unchecked"}) public final class ListRewrite { private ASTNode parent; private ChildListPropertyDescriptor childListProperty; private ASTRewrite rewriter; /* package*/ ListRewrite(ASTRewrite rewriter, ASTNode parent, ChildListPropertyDescriptor childProperty) { this.rewriter= rewriter; this.parent= parent; this.childListProperty= childProperty; } private RewriteEventStore getRewriteStore() { return this.rewriter.getRewriteEventStore(); } private ListRewriteEvent getEvent() { return getRewriteStore().getListEvent(this.parent, this.childListProperty, true); }
Returns the parent of the list for which this list rewriter was created.
See Also:
Returns:the node that contains the list for which this list rewriter was created
Since:3.1
/** * Returns the parent of the list for which this list rewriter was created. * @return the node that contains the list for which this list rewriter was created * @see #getLocationInParent() * @since 3.1 */
public ASTNode getParent() { return this.parent; }
Returns the property of the parent node for which this list rewriter was created.
See Also:
Returns:the property of the parent node for which this list rewriter was created
Since:3.1
/** * Returns the property of the parent node for which this list rewriter was created. * * @return the property of the parent node for which this list rewriter was created * @see #getParent() * @since 3.1 */
public StructuralPropertyDescriptor getLocationInParent() { return this.childListProperty; }
Removes the given node from its parent's list property in the rewriter. The node must be contained in the list. The AST itself is not actually modified in any way; rather, the rewriter just records a note that this node has been removed from this list.
Params:
  • node – the node being removed. The node can either be an original node in this list or (since 3.4) a new node already inserted or used as replacement in this AST rewriter.
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node is null, or if the node is not part of this rewriter's AST, or if the described modification is invalid (not a member of this node's original list)
/** * Removes the given node from its parent's list property in the rewriter. * The node must be contained in the list. * The AST itself is not actually modified in any way; rather, the rewriter * just records a note that this node has been removed from this list. * * @param node the node being removed. The node can either be an original node in this list * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node is null, or if the node is not * part of this rewriter's AST, or if the described modification is invalid * (not a member of this node's original list) */
public void remove(ASTNode node, TextEditGroup editGroup) { if (node == null) { throw new IllegalArgumentException(); } RewriteEvent event= getEvent().removeEntry(node); if (editGroup != null) { getRewriteStore().setEventEditGroup(event, editGroup); } }
Returns the ASTRewrite instance from which this ListRewriter has been created from.
Returns:the parent AST Rewriter instance.
Since:3.1
/** * Returns the ASTRewrite instance from which this ListRewriter has been created from. * @return the parent AST Rewriter instance. * @since 3.1 */
public ASTRewrite getASTRewrite() { return this.rewriter; }
Replaces the given node from its parent's list property in the rewriter. The node must be contained in the list. The replacement node must either be brand new (not part of the original AST) or a placeholder node (for example, one created by ASTRewrite.createCopyTarget(ASTNode), ASTRewrite.createMoveTarget(ASTNode), or ASTRewrite.createStringPlaceholder(String, int)). The AST itself is not actually modified in any way; rather, the rewriter just records a note that this node has been replaced in this list.
Params:
  • node – the node being removed. The node can either be an original node in this list or (since 3.4) a new node already inserted or used as replacement in this AST rewriter.
  • replacement – the replacement node, or null if no replacement
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node is null, or if the node is not part of this rewriter's AST, or if the replacement node is not a new node (or placeholder), or if the described modification is otherwise invalid (not a member of this node's original list)
/** * Replaces the given node from its parent's list property in the rewriter. * The node must be contained in the list. * The replacement node must either be brand new (not part of the original AST) * or a placeholder node (for example, one created by * {@link ASTRewrite#createCopyTarget(ASTNode)}, * {@link ASTRewrite#createMoveTarget(ASTNode)}, * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself * is not actually modified in any way; rather, the rewriter just records * a note that this node has been replaced in this list. * * @param node the node being removed. The node can either be an original node in this list * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. * @param replacement the replacement node, or <code>null</code> if no * replacement * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node is null, or if the node is not part * of this rewriter's AST, or if the replacement node is not a new node (or * placeholder), or if the described modification is otherwise invalid * (not a member of this node's original list) */
public void replace(ASTNode node, ASTNode replacement, TextEditGroup editGroup) { if (node == null) { throw new IllegalArgumentException(); } validatePropertyType(node); RewriteEvent event= getEvent().replaceEntry(node, replacement); if (editGroup != null) { getRewriteStore().setEventEditGroup(event, editGroup); } }
Inserts the given node into the list after the given element. The existing node previousElement must be in the list, either as an original or as a new node that has been inserted. The inserted node must either be brand new (not part of the original AST) or a placeholder node (for example, one created by ASTRewrite.createCopyTarget(ASTNode), ASTRewrite.createMoveTarget(ASTNode), or ASTRewrite.createStringPlaceholder(String, int)). The AST itself is not actually modified in any way; rather, the rewriter just records a note that this node has been inserted into the list.
Params:
  • node – the node to insert
  • previousElement – the element after which the given node is to be inserted
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node or element is null, or if the node is not part of this rewriter's AST, or if the inserted node is not a new node (or placeholder), or if previousElement is not a member of the list (original or new), or if the described modification is otherwise invalid
/** * Inserts the given node into the list after the given element. * The existing node <code>previousElement</code> must be in the list, either as an original or as a new * node that has been inserted. * The inserted node must either be brand new (not part of the original AST) * or a placeholder node (for example, one created by * {@link ASTRewrite#createCopyTarget(ASTNode)}, * {@link ASTRewrite#createMoveTarget(ASTNode)}, * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself * is not actually modified in any way; rather, the rewriter just records * a note that this node has been inserted into the list. * * @param node the node to insert * @param previousElement the element after which the given node is to be inserted * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node or element is null, * or if the node is not part of this rewriter's AST, or if the inserted node * is not a new node (or placeholder), or if <code>previousElement</code> is not a member * of the list (original or new), or if the described modification is * otherwise invalid */
public void insertAfter(ASTNode node, ASTNode previousElement, TextEditGroup editGroup) { if (node == null || previousElement == null) { throw new IllegalArgumentException(); } int index= getEvent().getIndex(previousElement, ListRewriteEvent.BOTH); if (index == -1) { throw new IllegalArgumentException("Node does not exist"); //$NON-NLS-1$ } internalInsertAt(node, index + 1, true, editGroup); }
Inserts the given node into the list before the given element. The existing node nextElement must be in the list, either as an original or as a new node that has been inserted. The inserted node must either be brand new (not part of the original AST) or a placeholder node (for example, one created by ASTRewrite.createCopyTarget(ASTNode), ASTRewrite.createMoveTarget(ASTNode), or ASTRewrite.createStringPlaceholder(String, int)). The AST itself is not actually modified in any way; rather, the rewriter just records a note that this node has been inserted into the list.
Params:
  • node – the node to insert
  • nextElement – the element before which the given node is to be inserted
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node or next element is null, or if the node is not part of this rewriter's AST, or if the inserted node is not a new node (or placeholder), or if nextElement is not a member of the list (original or new), or if the described modification is otherwise invalid
/** * Inserts the given node into the list before the given element. * The existing node <code>nextElement</code> must be in the list, either as an original or as a new * node that has been inserted. * The inserted node must either be brand new (not part of the original AST) * or a placeholder node (for example, one created by * {@link ASTRewrite#createCopyTarget(ASTNode)}, * {@link ASTRewrite#createMoveTarget(ASTNode)}, * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself * is not actually modified in any way; rather, the rewriter just records * a note that this node has been inserted into the list. * * @param node the node to insert * @param nextElement the element before which the given node is to be inserted * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node or next element is null, * or if the node is not part of this rewriter's AST, or if the inserted node * is not a new node (or placeholder), or if <code>nextElement</code> is not a member * of the list (original or new), or if the described modification is * otherwise invalid */
public void insertBefore(ASTNode node, ASTNode nextElement, TextEditGroup editGroup) { if (node == null || nextElement == null) { throw new IllegalArgumentException(); } int index= getEvent().getIndex(nextElement, ListRewriteEvent.BOTH); if (index == -1) { throw new IllegalArgumentException("Node does not exist"); //$NON-NLS-1$ } internalInsertAt(node, index, false, editGroup); }
Inserts the given node into the list at the start of the list. Equivalent to insertAt(node, 0, editGroup).
Params:
  • node – the node to insert
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node is null, or if the node is not part of this rewriter's AST, or if the inserted node is not a new node (or placeholder), or if the described modification is otherwise invalid (not a member of this node's original list)
See Also:
/** * Inserts the given node into the list at the start of the list. * Equivalent to <code>insertAt(node, 0, editGroup)</code>. * * @param node the node to insert * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node is null, or if the node is not part * of this rewriter's AST, or if the inserted node is not a new node (or * placeholder), or if the described modification is otherwise invalid * (not a member of this node's original list) * @see #insertAt(ASTNode, int, TextEditGroup) */
public void insertFirst(ASTNode node, TextEditGroup editGroup) { if (node == null) { throw new IllegalArgumentException(); } internalInsertAt(node, 0, false, editGroup); }
Inserts the given node into the list at the end of the list. Equivalent to insertAt(node, -1, editGroup).
Params:
  • node – the node to insert
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node is null, or if the node is not part of this rewriter's AST, or if the inserted node is not a new node (or placeholder), or if the described modification is otherwise invalid (not a member of this node's original list)
See Also:
/** * Inserts the given node into the list at the end of the list. * Equivalent to <code>insertAt(node, -1, editGroup)</code>. * * @param node the node to insert * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node is null, or if the node is not part * of this rewriter's AST, or if the inserted node is not a new node (or * placeholder), or if the described modification is otherwise invalid * (not a member of this node's original list) * @see #insertAt(ASTNode, int, TextEditGroup) */
public void insertLast(ASTNode node, TextEditGroup editGroup) { if (node == null) { throw new IllegalArgumentException(); } internalInsertAt(node, -1, true, editGroup); }
Inserts the given node into the list at the given index. The index corresponds to a combined list of original and new nodes; removed or replaced nodes are still in the combined list. The inserted node must either be brand new (not part of the original AST) or a placeholder node (for example, one created by ASTRewrite.createCopyTarget(ASTNode), ASTRewrite.createMoveTarget(ASTNode), or ASTRewrite.createStringPlaceholder(String, int)). The AST itself is not actually modified in any way; rather, the rewriter just records a note that this node has been inserted into the list.
Params:
  • node – the node to insert
  • index – insertion index in the combined list of original and inserted nodes; -1 indicates insertion as the last element
  • editGroup – the edit group in which to collect the corresponding text edits, or null if ungrouped
Throws:
  • IllegalArgumentException – if the node is null, or if the node is not part of this rewriter's AST, or if the inserted node is not a new node (or placeholder), or if the described modification is otherwise invalid (not a member of this node's original list)
  • IndexOutOfBoundsException – if the index is negative and not -1, or if it is larger than the size of the combined list
/** * Inserts the given node into the list at the given index. * The index corresponds to a combined list of original and new nodes; * removed or replaced nodes are still in the combined list. * The inserted node must either be brand new (not part of the original AST) * or a placeholder node (for example, one created by * {@link ASTRewrite#createCopyTarget(ASTNode)}, * {@link ASTRewrite#createMoveTarget(ASTNode)}, * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself * is not actually modified in any way; rather, the rewriter just records * a note that this node has been inserted into the list. * * @param node the node to insert * @param index insertion index in the combined list of original and * inserted nodes; <code>-1</code> indicates insertion as the last element * @param editGroup the edit group in which to collect the corresponding * text edits, or <code>null</code> if ungrouped * @throws IllegalArgumentException if the node is null, or if the node is not part * of this rewriter's AST, or if the inserted node is not a new node (or * placeholder), or if the described modification is otherwise invalid * (not a member of this node's original list) * @throws IndexOutOfBoundsException if the index is negative and not -1, * or if it is larger than the size of the combined list */
public void insertAt(ASTNode node, int index, TextEditGroup editGroup) { if (node == null) { throw new IllegalArgumentException(); } internalInsertAt(node, index, isInsertBoundToPreviousByDefault(node), editGroup); } private void internalInsertAt(ASTNode node, int index, boolean boundToPrevious, TextEditGroup editGroup) { validatePropertyType(node); RewriteEvent event= getEvent().insert(node, index); if (boundToPrevious) { getRewriteStore().setInsertBoundToPrevious(node); } if (editGroup != null) { getRewriteStore().setEventEditGroup(event, editGroup); } } private void validatePropertyType(ASTNode node) { if (!RewriteEventStore.DEBUG) { return; } if (!this.childListProperty.getElementType().isAssignableFrom(node.getClass())) { String message = node.getClass().getName() + " is not a valid type for " + this.childListProperty.getNodeClass().getName() //$NON-NLS-1$ + " property '" + this.childListProperty.getId() + "'. Must be " + this.childListProperty.getElementType().getName(); //$NON-NLS-1$ //$NON-NLS-2$ throw new IllegalArgumentException(message); } } private ASTNode createTargetNode(ASTNode first, ASTNode last, boolean isMove, ASTNode replacingNode, TextEditGroup editGroup) { if (first == null || last == null) { throw new IllegalArgumentException(); } NodeInfoStore nodeStore= this.rewriter.getNodeStore(); ASTNode placeholder= nodeStore.newPlaceholderNode(first.getNodeType()); // revisit: could use list type if (placeholder == null) { throw new IllegalArgumentException("Creating a target node is not supported for nodes of type" + first.getClass().getName()); //$NON-NLS-1$ } Block internalPlaceHolder= nodeStore.createCollapsePlaceholder(); CopySourceInfo info= getRewriteStore().createRangeCopy(this.parent, this.childListProperty, first, last, isMove, internalPlaceHolder, replacingNode, editGroup); nodeStore.markAsCopyTarget(placeholder, info); return placeholder; }
Creates and returns a placeholder node for a true copy of a range of nodes of the current list. The placeholder node can either be inserted as new or used to replace an existing node. When the document is rewritten, a copy of the source code for the given node range is inserted into the output document at the position corresponding to the placeholder (indentation is adjusted).
Params:
  • first – the node that starts the range
  • last – the node that ends the range
Throws:
  • IllegalArgumentException – An exception is thrown if the first or last node are null, if a node is not a child of the current list or if the first node is not before the last node. An IllegalArgumentException is also thrown if the copied range is overlapping with an other moved or copied range.
Returns:the new placeholder node
/** * Creates and returns a placeholder node for a true copy of a range of nodes of the * current list. * The placeholder node can either be inserted as new or used to replace an * existing node. When the document is rewritten, a copy of the source code * for the given node range is inserted into the output document at the position * corresponding to the placeholder (indentation is adjusted). * * @param first the node that starts the range * @param last the node that ends the range * @return the new placeholder node * @throws IllegalArgumentException An exception is thrown if the first or last node * are <code>null</code>, if a node is not a child of the current list or if the first node * is not before the last node. An <code>IllegalArgumentException</code> is * also thrown if the copied range is overlapping with an other moved or copied range. */
public final ASTNode createCopyTarget(ASTNode first, ASTNode last) { if (first == last) { return this.rewriter.createCopyTarget(first); } else { return createTargetNode(first, last, false, null, null); } }
Creates and returns a placeholder node for a move of a range of nodes of the current list. The placeholder node can either be inserted as new or used to replace an existing node. When the document is rewritten, a copy of the source code for the given node range is inserted into the output document at the position corresponding to the placeholder (indentation is adjusted).
Params:
  • first – the node that starts the range
  • last – the node that ends the range
Throws:
  • IllegalArgumentException – An exception is thrown if the first or last node are null, if a node is not a child of the current list or if the first node is not before the last node. An IllegalArgumentException is also thrown if the moved range is overlapping with an other moved or copied range.
Returns:the new placeholder node
Since:3.1
/** * Creates and returns a placeholder node for a move of a range of nodes of the * current list. * The placeholder node can either be inserted as new or used to replace an * existing node. When the document is rewritten, a copy of the source code * for the given node range is inserted into the output document at the position * corresponding to the placeholder (indentation is adjusted). * * @param first the node that starts the range * @param last the node that ends the range * @return the new placeholder node * @throws IllegalArgumentException An exception is thrown if the first or last node * are <code>null</code>, if a node is not a child of the current list or if the first node * is not before the last node. An <code>IllegalArgumentException</code> is * also thrown if the moved range is overlapping with an other moved or copied range. * * @since 3.1 */
public final ASTNode createMoveTarget(ASTNode first, ASTNode last) { return createMoveTarget(first, last, null, null); }
Creates and returns a placeholder node for a move of a range of nodes of the current list. The moved nodes can optionally be replaced by a specified node. The placeholder node can either be inserted as new or used to replace an existing node. When the document is rewritten, a copy of the source code for the given node range is inserted into the output document at the position corresponding to the placeholder (indentation is adjusted).
Params:
  • first – the node that starts the range
  • last – the node that ends the range
  • replacingNode – a node that is set at the location of the moved nodes or null to remove all nodes
  • editGroup – the edit group in which to collect the corresponding text edits fro a replace, or null if ungrouped
Throws:
  • IllegalArgumentException – An exception is thrown if the first or last node are null, if a node is not a child of the current list or if the first node is not before the last node. An IllegalArgumentException is also thrown if the moved range is overlapping with an other moved or copied range.
Returns:the new placeholder node
Since:3.1
/** * Creates and returns a placeholder node for a move of a range of nodes of the * current list. The moved nodes can optionally be replaced by a specified node. * * The placeholder node can either be inserted as new or used to replace an * existing node. When the document is rewritten, a copy of the source code * for the given node range is inserted into the output document at the position * corresponding to the placeholder (indentation is adjusted). * * @param first the node that starts the range * @param last the node that ends the range * @param replacingNode a node that is set at the location of the moved nodes * or <code>null</code> to remove all nodes * @param editGroup the edit group in which to collect the corresponding * text edits fro a replace, or <code>null</code> if ungrouped * @return the new placeholder node * @throws IllegalArgumentException An exception is thrown if the first or * last node are <code>null</code>, if a node is not a child of the current list or * if the first node is not before the last node. An <code>IllegalArgumentException * </code> is also thrown if the moved range is overlapping with an other moved * or copied range. * * @since 3.1 */
public final ASTNode createMoveTarget(ASTNode first, ASTNode last, ASTNode replacingNode, TextEditGroup editGroup) { if (first == last) { replace(first, replacingNode, editGroup); return this.rewriter.createMoveTarget(first); } else { return createTargetNode(first, last, true, replacingNode, editGroup); } } /* * Heuristic to decide if a inserted node is bound to previous or the next sibling. */ private boolean isInsertBoundToPreviousByDefault(ASTNode node) { return (node instanceof Statement || node instanceof FieldDeclaration); }
Returns the original nodes in the list property managed by this rewriter. The returned list is unmodifiable.
Returns:a list of all original nodes in the list
/** * Returns the original nodes in the list property managed by this * rewriter. The returned list is unmodifiable. * * @return a list of all original nodes in the list */
public List getOriginalList() { List list= (List) getEvent().getOriginalValue(); return Collections.unmodifiableList(list); }
Returns the nodes in the revised list property managed by this rewriter. The returned list is unmodifiable.
Returns:a list of all nodes in the list taking into account all the described changes
/** * Returns the nodes in the revised list property managed by this * rewriter. The returned list is unmodifiable. * * @return a list of all nodes in the list taking into account * all the described changes */
public List getRewrittenList() { List list= (List) getEvent().getNewValue(); return Collections.unmodifiableList(list); } }