1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.jdom;
13 import java.util.Enumeration;
15 import net.sourceforge.phpdt.core.jdom.DOMException;
16 import net.sourceforge.phpdt.core.jdom.DOMFactory;
17 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
18 import net.sourceforge.phpdt.core.jdom.IDOMFactory;
19 import net.sourceforge.phpdt.core.jdom.IDOMMethod;
20 import net.sourceforge.phpdt.core.jdom.IDOMNode;
21 import net.sourceforge.phpdt.internal.compiler.util.Util;
22 import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
25 * DOMNode provides an implementation for <code>IDOMNode</code>.
28 * A node represents a document fragment. When a node is created, its contents
29 * are located in a contiguous range of a shared document. A shared document is
30 * a char array, and is shared in the sense that the contents of other document
31 * fragments may also be contained in the array.
34 * A node maintains indicies of relevant portions of its contents in the shared
35 * document. Thus the original document and indicies create a form from which to
36 * generate the contents of the document fragment. As attributes of a node are
37 * changed, the node attempts to maintain the original formatting by only
38 * replacing relevant portions of the shared document with the value of new
39 * attributes (that is, filling in the form with replacement values).
42 * When a node is first created, it is considered unfragmented. When any
43 * attribute of the node is altered, the node is then considered fragmented from
44 * that point on. A node is also considered fragmented if any of its descendants
45 * are fragmented. When a node is unfragmented, the contents of the node can be
46 * efficiently generated from the original shared document. When a node is
47 * fragmented, the contents of the node must be created using the original
48 * document and indicies as a form, filling in replacement values as required.
51 * Generally, a node's contents consists of complete lines in a shared document.
52 * The contents of the node are normalized on creation to include any whitespace
53 * preceding the node on the line where the node begins, and to include and
54 * trailing whitespace up to the line where the next node begins. Any trailing //
55 * comments that begin on the line where the current node ends, are considered
60 public abstract class DOMNode implements IDOMNode {
63 * The first child of this node - <code>null</code> when this node has no
64 * children. (Children of a node are implemented as a doubly linked list).
66 protected DOMNode fFirstChild = null;
69 * The last child of this node - <code>null</code> when this node has no
70 * children. Used for efficient access to the last child when adding new
71 * children at the end of the linked list of children.
73 protected DOMNode fLastChild = null;
76 * The sibling node following this node - <code>null</code> for the last
77 * node in the sibling list.
79 protected DOMNode fNextNode = null;
82 * The parent of this node. A <code>null</code> parent indicates that this
83 * node is a root node of a document fragment.
85 protected DOMNode fParent = null;
88 * The sibling node preceding this node - <code>null</code> for the first
89 * node in the sibling list.
91 protected DOMNode fPreviousNode = null;
94 * True when this node has attributes that have been altered from their
95 * original state in the shared document, or when the attributes of a
96 * descendant have been altered. False when the contents of this node and
97 * all descendants are consistent with the content of the shared document.
99 protected boolean fIsFragmented = false;
102 * The name of this node. For efficiency, the name of a node is duplicated
103 * in this variable on creation, rather than always having to fetch the name
104 * from the shared document.
106 protected String fName = null;
109 * The original inclusive indicies of this node's name in the shared
110 * document. Values of -1 indiciate the name does not exist in the document.
112 protected int[] fNameRange;
115 * The shared document that the contents for this node are contained in.
116 * Attribute indicies are positions in this character array.
118 protected char[] fDocument = null;
121 * The original entire inclusive range of this node's contents within its
122 * document. Values of -1 indicate the contents of this node do not exist in
125 protected int[] fSourceRange;
128 * The current state of bit masks defined by this node. Initially all bit
129 * flags are turned off. All bit masks are defined by this class to avoid
130 * overlap, although bit masks are node type specific.
135 protected int fStateMask = 0;
138 * This position is the position of the end of the last line separator
139 * before the closing brace starting position of the receiver.
141 protected int fInsertionPosition;
144 * A bit mask indicating this field has an initializer expression
146 protected static final int MASK_FIELD_HAS_INITIALIZER = 0x00000001;
149 * A bit mask indicating this field is a secondary variable declarator for a
150 * previous field declaration.
152 protected static final int MASK_FIELD_IS_VARIABLE_DECLARATOR = 0x00000002;
155 * A bit mask indicating this field's type has been altered from its
156 * original contents in the document.
158 protected static final int MASK_FIELD_TYPE_ALTERED = 0x00000004;
161 * A bit mask indicating this node's name has been altered from its original
162 * contents in the document.
164 protected static final int MASK_NAME_ALTERED = 0x00000008;
167 * A bit mask indicating this node currently has a body.
169 protected static final int MASK_HAS_BODY = 0x00000010;
172 * A bit mask indicating this node currently has a preceding comment.
174 protected static final int MASK_HAS_COMMENT = 0x00000020;
177 * A bit mask indicating this method is a constructor.
179 protected static final int MASK_IS_CONSTRUCTOR = 0x00000040;
182 * A bit mask indicating this type is a class.
184 protected static final int MASK_TYPE_IS_CLASS = 0x00000080;
187 * A bit mask indicating this type has a superclass (requires or has an
190 protected static final int MASK_TYPE_HAS_SUPERCLASS = 0x00000100;
193 * A bit mask indicating this type implements or extends some interfaces
195 protected static final int MASK_TYPE_HAS_INTERFACES = 0x00000200;
198 * A bit mask indicating this return type of this method has been altered
199 * from the original contents.
201 protected static final int MASK_RETURN_TYPE_ALTERED = 0x00000400;
204 * A bit mask indicating this node has detailed source indexes
206 protected static final int MASK_DETAILED_SOURCE_INDEXES = 0x00000800;
209 * Creates a new empty document fragment.
214 fSourceRange = new int[] { -1, -1 };
215 fNameRange = new int[] { -1, -1 };
220 * Creates a new document fragment on the given range of the document.
223 * the document containing this node's original contents
224 * @param sourceRange -
225 * a two element array of integers describing the entire
226 * inclusive source range of this node within its document.
227 * Contents start on and include the character at the first
228 * position. Contents end on and include the character at the
229 * last position. An array of -1's indicates this node's contents
230 * do not exist in the document.
232 * the identifier portion of the name of this node, or
233 * <code>null</code> if this node does not have a name
235 * a two element array of integers describing the entire
236 * inclusive source range of this node's name within its
237 * document, including any array qualifiers that might
238 * immediately follow the name or -1's if this node does not have
241 DOMNode(char[] document, int[] sourceRange, String name, int[] nameRange) {
243 fDocument = document;
244 fSourceRange = sourceRange;
246 fNameRange = nameRange;
251 * Adds the given un-parented node (document fragment) as the last child of
255 * When a child is added, this node must be considered fragmented such that
256 * the contents of this node are properly generated.
258 * @see IDOMNode#addChild(IDOMNode)
260 public void addChild(IDOMNode child) throws IllegalArgumentException,
262 basicAddChild(child);
264 // if the node is a constructor, it must also be fragmented to update
265 // the constructor's name
266 if (child.getNodeType() == IDOMNode.METHOD
267 && ((IDOMMethod) child).isConstructor()) {
268 ((DOMNode) child).fragment();
275 * Appends the current contents of this document fragment to the given
276 * <code>CharArrayBuffer</code>.
279 * If this node is fragmented, contents must be generated by using the
280 * original document and indicies as a form for the current attribute values
281 * of this node. If this node not fragmented, the contents can be obtained
285 protected void appendContents(CharArrayBuffer buffer) {
286 if (isFragmented()) {
287 appendFragmentedContents(buffer);
289 buffer.append(fDocument, fSourceRange[0], fSourceRange[1] + 1
295 * Appends the contents of all children of this node to the given
296 * <code>CharArrayBuffer</code>.
299 * This algorithm used minimizes String generation by merging adjacent
300 * unfragmented children into one substring operation.
303 protected void appendContentsOfChildren(CharArrayBuffer buffer) {
304 DOMNode child = fFirstChild;
307 int start = 0, end = 0;
309 start = child.getStartPosition();
310 end = child.getEndPosition();
312 while (child != null) {
313 sibling = child.fNextNode;
314 if (sibling != null) {
315 if (sibling.isContentMergableWith(child)) {
316 end = sibling.getEndPosition();
318 if (child.isFragmented()) {
319 child.appendContents(buffer);
321 buffer.append(child.getDocument(), start, end + 1
324 start = sibling.getStartPosition();
325 end = sibling.getEndPosition();
328 if (child.isFragmented()) {
329 child.appendContents(buffer);
331 buffer.append(child.getDocument(), start, end + 1 - start);
339 * Appends the contents of this node to the given
340 * <code>CharArrayBufer</code>, using the original document and indicies
341 * as a form for the current attribute values of this node.
343 protected abstract void appendFragmentedContents(CharArrayBuffer buffer);
346 * Adds the given un-parented node (document fragment) as the last child of
347 * this node without setting this node's 'fragmented' flag. This method is
348 * only used by the <code>DOMBuilder</code> when creating a new DOM such
349 * that a new DOM is unfragmented.
351 void basicAddChild(IDOMNode child) throws IllegalArgumentException,
353 // verify child may be added
354 if (!canHaveChildren()) {
355 throw new DOMException(Util.bind("dom.unableAddChild")); //$NON-NLS-1$
358 throw new IllegalArgumentException(Util.bind("dom.addNullChild")); //$NON-NLS-1$
360 if (!isAllowableChild(child)) {
361 throw new DOMException(Util.bind("dom.addIncompatibleChild")); //$NON-NLS-1$
363 if (child.getParent() != null) {
364 throw new DOMException(Util.bind("dom.addChildWithParent")); //$NON-NLS-1$
367 * NOTE: To test if the child is an ancestor of this node, we need only
368 * test if the root of this node is the child (the child is already a
369 * root since we have just guarenteed it has no parent).
371 if (child == getRoot()) {
372 throw new DOMException(Util.bind("dom.addAncestorAsChild")); //$NON-NLS-1$
375 DOMNode node = (DOMNode) child;
377 // if the child is not already part of this document, localize its
379 // before adding it to the tree
380 if (node.getDocument() != getDocument()) {
381 node.localizeContents();
384 // add the child last
385 if (fFirstChild == null) {
386 // this is the first and only child
389 fLastChild.fNextNode = node;
390 node.fPreviousNode = fLastChild;
397 * Generates detailed source indexes for this node if possible.
399 * @exception DOMException
400 * if unable to generate detailed source indexes for this
403 protected void becomeDetailed() throws DOMException {
405 DOMNode detailed = getDetailedNode();
406 if (detailed == null) {
407 throw new DOMException(Util.bind("dom.cannotDetail")); //$NON-NLS-1$
409 if (detailed != this) {
410 shareContents(detailed);
416 * Returns true if this node is allowed to have children, otherwise false.
419 * Default implementation of <code>IDOMNode</code> interface method
420 * returns false; this method must be overridden by subclasses that
421 * implement nodes that allow children.
423 * @see IDOMNode#canHaveChildren()
425 public boolean canHaveChildren() {
430 * @see IDOMNode#clone()
432 public Object clone() {
434 // create a new buffer with all my contents and children contents
436 char[] buffer = null;
437 int offset = fSourceRange[0];
440 length = fSourceRange[1] - offset + 1;
441 buffer = new char[length];
442 System.arraycopy(fDocument, offset, buffer, 0, length);
444 DOMNode clone = newDOMNode();
445 clone.shareContents(this);
446 clone.fDocument = buffer;
449 clone.offset(0 - offset);
453 if (canHaveChildren()) {
454 Enumeration children = getChildren();
455 while (children.hasMoreElements()) {
456 DOMNode child = (DOMNode) children.nextElement();
457 if (child.fDocument == fDocument) {
458 DOMNode childClone = child.cloneSharingDocument(buffer,
460 clone.basicAddChild(childClone);
462 DOMNode childClone = (DOMNode) child.clone();
463 clone.addChild(childClone);
472 private DOMNode cloneSharingDocument(char[] document, int rootOffset) {
474 DOMNode clone = newDOMNode();
475 clone.shareContents(this);
476 clone.fDocument = document;
477 if (rootOffset > 0) {
478 clone.offset(0 - rootOffset);
481 if (canHaveChildren()) {
482 Enumeration children = getChildren();
483 while (children.hasMoreElements()) {
484 DOMNode child = (DOMNode) children.nextElement();
485 if (child.fDocument == fDocument) {
486 DOMNode childClone = child.cloneSharingDocument(document,
488 clone.basicAddChild(childClone);
490 DOMNode childClone = (DOMNode) child.clone();
491 clone.addChild(childClone);
499 * Sets this node's fragmented flag and all ancestor fragmented flags to
500 * <code>true<code>. This happens when an attribute of this node or a descendant
501 * node has been altered. When a node is fragmented, its contents must
502 * be generated from its attributes and original "form" rather than
503 * from the original contents in the document.
505 protected void fragment() {
506 if (!isFragmented()) {
507 fIsFragmented = true;
508 if (fParent != null) {
515 * @see IDOMNode#getCharacters()
517 public char[] getCharacters() {
518 CharArrayBuffer buffer = new CharArrayBuffer();
519 appendContents(buffer);
520 return buffer.getContents();
524 * @see IDOMNode#getChild(String)
526 public IDOMNode getChild(String name) {
527 DOMNode child = fFirstChild;
528 while (child != null) {
529 String n = child.getName();
535 if (name.equals(n)) {
539 child = child.fNextNode;
545 * @see IDOMNode#getChildren()
547 public Enumeration getChildren() {
548 return new SiblingEnumeration(fFirstChild);
552 * Returns the current contents of this document fragment, or
553 * <code>null</code> if this node has no contents.
556 * If this node is fragmented, contents must be generated by using the
557 * original document and indicies as a form for the current attribute values
558 * of this node. If this node not fragmented, the contents can be obtained
561 * @see IDOMNode#getContents()
563 public String getContents() {
564 CharArrayBuffer buffer = new CharArrayBuffer();
565 appendContents(buffer);
566 return buffer.toString();
570 * Returns a new document fragment representing this node with detailed
571 * source indexes. Subclasses that provide a detailed implementation must
572 * override this method.
574 protected DOMNode getDetailedNode() {
579 * Returns the document containing this node's original contents. The
580 * document may be shared by other nodes.
582 protected char[] getDocument() {
587 * Returns the original position of the last character of this node's
588 * contents in its document.
590 public int getEndPosition() {
591 return fSourceRange[1];
595 * Returns a factory with which to create new document fragments.
597 protected IDOMFactory getFactory() {
598 return new DOMFactory();
602 * @see IDOMNode#getFirstChild()
604 public IDOMNode getFirstChild() {
609 * Returns the position at which the first child of this node should be
612 public int getInsertionPosition() {
613 return fInsertionPosition;
617 * Returns <code>true</code> if the given mask of this node's state flag
618 * is turned on, otherwise <code>false</code>.
620 protected boolean getMask(int mask) {
621 return (fStateMask & mask) > 0;
625 * @see IDOMNode#getName()
627 public String getName() {
632 * Returns the source code to be used for this node's name.
634 protected char[] getNameContents() {
635 if (isNameAltered()) {
636 return fName.toCharArray();
638 if (fName == null || fNameRange[0] < 0) {
641 int length = fNameRange[1] + 1 - fNameRange[0];
642 char[] result = new char[length];
643 System.arraycopy(fDocument, fNameRange[0], result, 0, length);
650 * @see IDOMNode#getNextNode()
652 public IDOMNode getNextNode() {
657 * @see IDOMNode#getParent()
659 public IDOMNode getParent() {
664 * Answers a source position which corresponds to the end of the parent
665 * element's declaration.
667 protected int getParentEndDeclaration() {
668 IDOMNode parent = getParent();
669 if (parent == null) {
672 if (parent instanceof IDOMCompilationUnit) {
675 return ((DOMType) parent).getOpenBodyEnd();
681 * @see IDOMNode#getPreviousNode()
683 public IDOMNode getPreviousNode() {
684 return fPreviousNode;
688 * Returns the root node of this document fragment.
690 protected IDOMNode getRoot() {
691 if (fParent == null) {
694 return fParent.getRoot();
699 * Returns the original position of the first character of this node's
700 * contents in its document.
702 public int getStartPosition() {
703 return fSourceRange[0];
707 * @see IDOMNode#insertSibling(IDOMNode)
709 public void insertSibling(IDOMNode sibling)
710 throws IllegalArgumentException, DOMException {
711 // verify sibling may be added
712 if (sibling == null) {
713 throw new IllegalArgumentException(Util.bind("dom.addNullSibling")); //$NON-NLS-1$
715 if (fParent == null) {
716 throw new DOMException(Util.bind("dom.addSiblingBeforeRoot")); //$NON-NLS-1$
718 if (!fParent.isAllowableChild(sibling)) {
719 throw new DOMException(Util.bind("dom.addIncompatibleSibling")); //$NON-NLS-1$
721 if (sibling.getParent() != null) {
722 throw new DOMException(Util.bind("dom.addSiblingWithParent")); //$NON-NLS-1$
725 * NOTE: To test if the sibling is an ancestor of this node, we need
726 * only test if the root of this node is the child (the sibling is
727 * already a root since we have just guaranteed it has no parent).
729 if (sibling == getRoot()) {
730 throw new DOMException(Util.bind("dom.addAncestorAsSibling")); //$NON-NLS-1$
733 DOMNode node = (DOMNode) sibling;
735 // if the sibling is not already part of this document, localize its
737 // before inserting it into the tree
738 if (node.getDocument() != getDocument()) {
739 node.localizeContents();
743 if (fPreviousNode == null) {
744 fParent.fFirstChild = node;
746 fPreviousNode.fNextNode = node;
748 node.fParent = fParent;
749 node.fPreviousNode = fPreviousNode;
750 node.fNextNode = this;
751 fPreviousNode = node;
753 // if the node is a constructor, it must also be fragmented to update
754 // the constructor's name
755 if (node.getNodeType() == IDOMNode.METHOD
756 && ((IDOMMethod) node).isConstructor()) {
766 public boolean isAllowableChild(IDOMNode node) {
771 * Returns <code>true</code> if the contents of this node are from the
772 * same document as the given node, the contents of this node immediately
773 * follow the contents of the given node, and neither this node or the given
774 * node are fragmented - otherwise <code>false</code>.
776 protected boolean isContentMergableWith(DOMNode node) {
777 return !node.isFragmented() && !isFragmented()
778 && node.getDocument() == getDocument()
779 && node.getEndPosition() + 1 == getStartPosition();
783 * Returns <code>true</code> if this node has detailed source index
784 * information, or <code>false</code> if this node has limited source
785 * index information. To perform some manipulations, detailed indexes are
788 protected boolean isDetailed() {
789 return getMask(MASK_DETAILED_SOURCE_INDEXES);
793 * Returns <code>true</code> if this node's or a descendant node's
794 * contents have been altered since this node was created. This indicates
795 * that the contents of this node are no longer consistent with the contents
796 * of this node's document.
798 protected boolean isFragmented() {
799 return fIsFragmented;
803 * Returns <code>true</code> if this noed's name has been altered from the
804 * original document contents.
806 protected boolean isNameAltered() {
807 return getMask(MASK_NAME_ALTERED);
811 * @see IDOMNode#isSignatureEqual(IDOMNode).
814 * By default, the signatures of two nodes are equal if their type and names
815 * are equal. Node types that have other requirements for equality must
816 * override this method.
818 public boolean isSignatureEqual(IDOMNode node) {
819 return getNodeType() == node.getNodeType()
820 && getName().equals(node.getName());
824 * Localizes the contents of this node and all descendant nodes, such that
825 * this node is no longer dependent on its original document in order to
826 * generate its contents. This node and all descendant nodes become
827 * unfragmented and share a new document.
829 protected void localizeContents() {
831 DOMNode clone = (DOMNode) clone();
832 shareContents(clone);
837 * Returns a new empty <code>DOMNode</code> for this instance.
839 protected abstract DOMNode newDOMNode();
842 * Normalizes this <code>DOMNode</code>'s source positions to include
843 * whitespace preceeding the node on the line on which the node starts, and
844 * all whitespace after the node up to the next node's start
846 void normalize(ILineStartFinder finder) {
847 if (getPreviousNode() == null)
848 normalizeStartPosition(getParentEndDeclaration(), finder);
850 // Set the children's position
851 if (canHaveChildren()) {
852 Enumeration children = getChildren();
853 while (children.hasMoreElements())
854 ((DOMNode) children.nextElement()).normalize(finder);
857 normalizeEndPosition(finder, (DOMNode) getNextNode());
861 * Normalizes this <code>DOMNode</code>'s end position.
863 void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
865 // this node's end position includes all of the characters up
866 // to the end of the enclosing node
867 DOMNode parent = (DOMNode) getParent();
868 if (parent == null || parent instanceof DOMCompilationUnit) {
869 setSourceRangeEnd(fDocument.length - 1);
872 int temp = ((DOMType) parent).getCloseBodyPosition() - 1;
873 setSourceRangeEnd(temp);
874 fInsertionPosition = Math.max(finder.getLineStart(temp + 1),
878 // this node's end position is just before the start of the next
880 int temp = next.getStartPosition() - 1;
881 fInsertionPosition = Math.max(finder.getLineStart(temp + 1),
883 next.normalizeStartPosition(getEndPosition(), finder);
884 setSourceRangeEnd(next.getStartPosition() - 1);
889 * Normalizes this <code>DOMNode</code>'s start position.
891 void normalizeStartPosition(int previousEnd, ILineStartFinder finder) {
892 int nodeStart = getStartPosition();
893 int lineStart = finder.getLineStart(nodeStart);
894 if (nodeStart > lineStart
895 && (lineStart > previousEnd || (previousEnd == 0 && lineStart == 0)))
896 setStartPosition(lineStart);
900 * Offsets all the source indexes in this node by the given amount.
902 protected void offset(int offset) {
903 offsetRange(fNameRange, offset);
904 offsetRange(fSourceRange, offset);
908 * Offsets the source range by the given amount
910 protected void offsetRange(int[] range, int offset) {
911 for (int i = 0; i < range.length; i++) {
920 * Returns a copy of the given range.
922 protected int[] rangeCopy(int[] range) {
923 int[] copy = new int[range.length];
924 for (int i = 0; i < range.length; i++) {
931 * Separates this node from its parent and siblings, maintaining any ties
932 * that this node has to the underlying document fragment.
935 * When a child is removed, its parent is fragmented such that it properly
936 * generates its contents.
938 * @see IDOMNode#remove()
940 public void remove() {
942 if (fParent != null) {
947 if (fNextNode != null) {
948 fNextNode.fPreviousNode = fPreviousNode;
950 if (fPreviousNode != null) {
951 fPreviousNode.fNextNode = fNextNode;
953 // fix parent's pointers
954 if (fParent != null) {
955 if (fParent.fFirstChild == this) {
956 fParent.fFirstChild = fNextNode;
958 if (fParent.fLastChild == this) {
959 fParent.fLastChild = fPreviousNode;
965 fPreviousNode = null;
969 * Sets the specified mask of this node's state mask on or off based on the
970 * boolean value - true -> on, false -> off.
972 protected void setMask(int mask, boolean on) {
981 * @see IDOMNode#setName
983 public void setName(String name) {
985 setNameAltered(true);
990 * Sets the state of this node as having its name attribute altered from the
991 * original document contents.
993 protected void setNameAltered(boolean altered) {
994 setMask(MASK_NAME_ALTERED, altered);
998 * Sets the original position of the last character of this node's contents
999 * in its document. This method is only used during DOM creation while
1000 * normalizing the source range of each node.
1002 protected void setSourceRangeEnd(int end) {
1003 fSourceRange[1] = end;
1007 * Sets the original position of the first character of this node's contents
1008 * in its document. This method is only used during DOM creation while
1009 * normalizing the source range of each node.
1011 protected void setStartPosition(int start) {
1012 fSourceRange[0] = start;
1016 * Sets the contents of this node and descendant nodes to be the (identical)
1017 * contents of the given node and its descendants. This does not effect this
1018 * node's parent and sibling configuration, only the contents of this node.
1019 * This is used only to localize the contents of this node.
1021 protected void shareContents(DOMNode node) {
1022 fDocument = node.fDocument;
1023 fIsFragmented = node.fIsFragmented;
1025 fNameRange = rangeCopy(node.fNameRange);
1026 fSourceRange = rangeCopy(node.fSourceRange);
1027 fStateMask = node.fStateMask;
1029 if (canHaveChildren()) {
1030 Enumeration myChildren = getChildren();
1031 Enumeration otherChildren = node.getChildren();
1032 DOMNode myChild, otherChild;
1033 while (myChildren.hasMoreElements()) {
1034 myChild = (DOMNode) myChildren.nextElement();
1035 otherChild = (DOMNode) otherChildren.nextElement();
1036 myChild.shareContents(otherChild);
1042 * Returns a <code>String</code> representing this node - for Debug
1045 public abstract String toString();