new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / jdom / DOMField.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/jdom/DOMField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/jdom/DOMField.java
new file mode 100644 (file)
index 0000000..32ebdb1
--- /dev/null
@@ -0,0 +1,618 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core.jdom;
+
+import java.util.Enumeration;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.core.jdom.DOMException;
+import net.sourceforge.phpdt.core.jdom.IDOMField;
+import net.sourceforge.phpdt.core.jdom.IDOMNode;
+import net.sourceforge.phpdt.internal.compiler.util.Util;
+import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
+import net.sourceforge.phpdt.internal.core.util.CharArrayOps;
+
+/**
+ * DOMField provides an implementation of IDOMField.
+ *
+ * @see IDOMField
+ * @see DOMNode
+ */
+class DOMField extends DOMMember implements IDOMField {
+       
+       /**
+        * Contains the type of the field when the type
+        * has been altered from the contents in the
+        * document, otherwise <code>null</code>.
+        */
+       protected String fType;
+
+       /**
+        * The original inclusive source range of the
+        * field's type in the document.
+        */
+       protected int[] fTypeRange;
+               
+       /**
+        * The contents of the initializer when the
+        * initializer has been altered from the
+        * original state in the document, otherwise
+        * <code>null</code>.
+        */
+       protected String fInitializer;
+
+       /**
+        * The original inclusive source range of the
+        * initializer in the document.
+        */
+       protected int[] fInitializerRange;
+
+/**
+ * Constructs an empty field node.
+ */
+DOMField() {
+}
+/**
+ * Creates a new detailed FIELD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ *             entire inclusive source range of this node within its document.
+ *             Contents start on and include the character at the first position.
+ *             Contents end on and include the character at the last position.
+ *             An array of -1's indicates this node's contents do not exist
+ *             in the document.
+ * @param name - the identifier portion of the name of this field,
+ *             corresponding to VariableDeclaratorId (JLS 8.3).
+ * @param nameRange - a two element array of integers describing the
+ *             entire inclusive source range of this node's name within its document,
+ *             including any array qualifiers that might follow the name.
+ * @param commentRange - a two element array describing the comments that precede
+ *             the member declaration. The first matches the start of this node's
+ *             sourceRange, and the second is the new-line or first non-whitespace
+ *             character following the last comment. If no comments are present,
+ *             this array contains two -1's.
+ * @param flags - an integer representing the modifiers for this member. The
+ *             integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param modifierRange - a two element array describing the location of
+ *             modifiers for this member within its source range. The first integer
+ *             is the first character of the first modifier for this member, and
+ *             the second integer is the last whitespace character preceeding the
+ *             next part of this member declaration. If there are no modifiers present
+ *             in this node's source code (that is, package default visibility), this array
+ *             contains two -1's.
+ * @param typeRange- a two element array describing the location of the
+ *             typeName in the document - the positions of the first and last characters
+ *             of the typeName.
+ * @param type - the type of the field, in normalized form, as defined in
+ *      Type in Field Declaration (JLS 8.3)
+ * @param hasInitializer - true if this field declaration includes an initializer,
+ *             otherwise false
+ * @param initRange - a two element array describing the location of the initializer
+ *             in the declaration. The first integer is the position of the character
+ *             following the equals sign, and the position of the last character is the last
+ *             in the initializer. If this field has no initializer, this array contains
+ *             two -1's.
+ * @param isVariableDeclarator - true if the field is a seconday variable declarator
+ *             for a previous field declaration.
+ */
+DOMField(char[] document, int[] sourceRange, String name, int[] nameRange, int[] commentRange, int flags, int[] modifierRange, int[] typeRange, String type, boolean hasInitializer, int[] initRange, boolean isVariableDeclarator) {
+       super(document, sourceRange, name, nameRange, commentRange, flags, modifierRange);
+
+       fType= type;
+       fTypeRange= typeRange;
+       setHasInitializer(hasInitializer);
+       fInitializerRange= initRange;
+       setIsVariableDeclarator(isVariableDeclarator);
+       setMask(MASK_DETAILED_SOURCE_INDEXES, true);
+
+}
+/**
+ * Creates a new simple FIELD document fragment on the given range of the document.
+ *
+ * @param document - the document containing this node's original contents
+ * @param sourceRange - a two element array of integers describing the
+ *             entire inclusive source range of this node within its document.
+ *             Contents start on and include the character at the first position.
+ *             Contents end on and include the character at the last position.
+ *             An array of -1's indicates this node's contents do not exist
+ *             in the document.
+ * @param name - the identifier portion of the name of this field,
+ *             corresponding to VariableDeclaratorId (JLS 8.3).
+ * @param nameRange - a two element array of integers describing the
+ *             entire inclusive source range of this node's name within its document,
+ *             including any array qualifiers that might follow the name.
+ * @param flags - an integer representing the modifiers for this member. The
+ *             integer can be analyzed with org.eclipse.jdt.core.Flags
+ * @param type - the type of the field, in normalized form, as defined in
+ *      Type in Field Declaration (JLS 8.3)
+ * @param isVariableDeclarator - true if the field is a seconday variable declarator
+ *             for a previous field declaration.
+ */
+DOMField(char[] document, int[] sourceRange, String name, int[] nameRange, int flags, String type, boolean isVariableDeclarator) {
+       this(document, sourceRange, name, nameRange, new int[] {-1, -1}, flags, new int[] {-1, -1}, new int[] {-1, -1}, type, false, new int[] {-1, -1}, isVariableDeclarator);
+       setMask(MASK_DETAILED_SOURCE_INDEXES, false);
+}
+/**
+ * Appends this member's body contents to the given CharArrayBuffer.
+ * Body contents include the member body and any trailing whitespace.
+ *
+ * <p>A field does not have a body.
+ *
+ * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
+ */
+protected void appendMemberBodyContents(CharArrayBuffer buffer) {}
+/**
+ * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
+ */
+protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
+
+       if (isVariableDeclarator()) {
+               buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+       } else {
+               buffer
+                       .append(getTypeContents())
+                       .append(fDocument, fTypeRange[1] + 1, fNameRange[0] - fTypeRange[1] - 1);
+       }
+       
+       buffer.append(getNameContents());
+       if (hasInitializer()) {
+               if (fInitializerRange[0] < 0) {
+                       buffer
+                               .append('=')
+                               .append(fInitializer)
+                               .append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+               } else {
+                       buffer
+                               .append(fDocument, fNameRange[1] + 1, fInitializerRange[0] - fNameRange[1] - 1)
+                               .append(getInitializer())
+                               .append(fDocument, fInitializerRange[1] + 1, fSourceRange[1] - fInitializerRange[1]);
+               }
+       } else {
+               if (fInitializerRange[0] < 0) {
+                       buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+               } else {
+                       buffer.append(fDocument, fInitializerRange[1] + 1, fSourceRange[1] - fInitializerRange[1]);
+               }
+       }
+
+}
+/**
+ * Appends this member's header contents to the given CharArrayBuffer.
+ * Header contents include any preceding comments and modifiers.
+ *
+ * <p>If this field is a secondary variable declarator, there is no header.
+ *
+ * @see DOMMember#appendMemberHeaderFragment(CharArrayBuffer)
+ */
+protected void appendMemberHeaderFragment(CharArrayBuffer buffer) {
+
+       if (isVariableDeclarator()) {
+               return;
+       } else {
+               super.appendMemberHeaderFragment(buffer);
+       }
+
+}
+/**
+ * @see DOMMember#appendSimpleContents(CharArrayBuffer)
+ */
+protected void appendSimpleContents(CharArrayBuffer buffer) {
+       // append eveything before my name
+       buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
+       // append my name
+       buffer.append(fName);
+       // append everything after my name
+       buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
+}
+/**
+ * Generates detailed source indexes for this node if possible.
+ *
+ * @exception DOMException if unable to generate detailed source indexes
+ *     for this node
+ */
+//protected void becomeDetailed() throws DOMException {
+//     if (!isDetailed()) {
+//             if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+//                     DOMNode first = getFirstFieldDeclaration();
+//                     DOMNode last = getLastFieldDeclaration();
+//                     DOMNode node= first;
+//                     String source= first.getContents();
+//                     while (node != last) {
+//                             node= node.fNextNode;
+//                             source+=node.getContents();
+//                     }
+//                     DOMBuilder builder = new DOMBuilder();
+//                     IDOMField[] details= builder.createFields(source.toCharArray());
+//                     if (details.length == 0) {
+//                             throw new DOMException(Util.bind("dom.cannotDetail")); //$NON-NLS-1$
+//                     } else {
+//                             node= this;
+//                             for (int i= 0; i < details.length; i++) {
+//                                     node.shareContents((DOMNode)details[i]);
+//                                     node= node.fNextNode;
+//                             }
+//                     }
+//             } else {
+//                     super.becomeDetailed();
+//             }
+//
+//     }
+//}
+/**
+ * @see IDOMNode#clone()
+ */
+public Object clone() {
+//     if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+//             return getFactory().createField(new String(getSingleVariableDeclaratorContents()));
+//     } else {
+               return super.clone();
+//     }
+}
+/**
+ * Expands all variable declarators in this field declaration into
+ * stand-alone field declarations. 
+ */
+protected void expand() {
+       if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+               Enumeration siblings= new SiblingEnumeration(getFirstFieldDeclaration());
+               DOMField field= (DOMField)siblings.nextElement();
+               DOMNode next= field.fNextNode;
+               while (siblings.hasMoreElements() && (next instanceof DOMField) && (((DOMField)next).isVariableDeclarator())) {
+                       field.localizeContents();
+                       if (field.fParent != null) {
+                               field.fParent.fragment();
+                       }
+                       field= (DOMField)siblings.nextElement();
+                       next= field.fNextNode;
+               }
+               field.localizeContents();
+       }
+}
+/**
+ * @see DOMNode#getDetailedNode()
+ */
+//protected DOMNode getDetailedNode() {
+//     if (isVariableDeclarator() || hasMultipleVariableDeclarators()) {
+//             return (DOMNode)getFactory().createField(new String(getSingleVariableDeclaratorContents()));
+//     } else {
+//             return (DOMNode)getFactory().createField(getContents());
+//     }
+//}
+/**
+ * Returns the first field document fragment that defines
+ * the type for this variable declarator.
+ */
+protected DOMField getFirstFieldDeclaration() {
+       if (isVariableDeclarator()) {
+               return ((DOMField)fPreviousNode).getFirstFieldDeclaration();
+       } else {
+               return this;
+       }
+}
+/**
+ * @see IDOMField#getInitializer()
+ */
+public String getInitializer() {
+       becomeDetailed();
+       if (hasInitializer()) {
+               if (fInitializer != null) {
+                       return fInitializer;
+               } else {
+                       return CharArrayOps.substring(fDocument, fInitializerRange[0], fInitializerRange[1] + 1 - fInitializerRange[0]);
+               }
+       } else {
+               return null;
+       }
+}
+/**
+ * @see IDOMNode#getJavaElement
+ */
+public IJavaElement getJavaElement(IJavaElement parent) throws IllegalArgumentException {
+       if (parent.getElementType() == IJavaElement.TYPE) {
+               return ((IType)parent).getField(getName());
+       } else {
+               throw new IllegalArgumentException(Util.bind("element.illegalParent")); //$NON-NLS-1$
+       }
+}
+/**
+ * Returns the last field document fragment in this muli-declarator statement.
+ */
+protected DOMField getLastFieldDeclaration() {
+       DOMField field = this;
+       while (field.isVariableDeclarator() || field.hasMultipleVariableDeclarators()) {
+               if (field.fNextNode instanceof DOMField && ((DOMField)field.fNextNode).isVariableDeclarator()) {
+                       field= (DOMField)field.fNextNode;
+               } else {
+                       break;
+               }
+       }
+       return field;
+}
+/**
+ * @see DOMMember#getMemberDeclarationStartPosition()
+ */
+protected int getMemberDeclarationStartPosition() {
+       return fTypeRange[0];
+}
+/**
+ * @see IDOMNode#getNodeType()
+ */
+public int getNodeType() {
+       return IDOMNode.FIELD;
+}
+/**
+ * Returns a String representing this field declaration as a field
+ * declaration with one variable declarator.
+ */
+protected char[] getSingleVariableDeclaratorContents() {
+
+
+       CharArrayBuffer buffer= new CharArrayBuffer();
+       DOMField first= getFirstFieldDeclaration();
+       if (first.isDetailed()) {
+               first.appendMemberHeaderFragment(buffer);
+               buffer.append(getType());
+               if (isVariableDeclarator()) {
+                       buffer.append(' ');
+               } else {
+                       buffer.append(fDocument, fTypeRange[1] + 1, fNameRange[0] - fTypeRange[1] - 1);
+               }
+       } else {
+               buffer.append(first.fDocument, first.fSourceRange[0], first.fNameRange[0] - first.fSourceRange[0]);
+       }
+       
+       buffer.append(getName());
+       if (hasInitializer()) {
+               if (fInitializerRange[0] < 0) {
+                       buffer
+                               .append('=')
+                               .append(fInitializer)
+                               .append(';')
+                               .append(Util.LINE_SEPARATOR);
+               } else {
+                       buffer
+                               .append(fDocument, fNameRange[1] + 1, fInitializerRange[0] - fNameRange[1] - 1)
+                               .append(getInitializer())
+                               .append(';')
+                               .append(Util.LINE_SEPARATOR);
+               }
+       } else {
+               buffer.append(';').append(Util.LINE_SEPARATOR);
+       }
+       return buffer.getContents();
+}
+/**
+ * @see IDOMField#getType()
+ */
+public String getType() {
+       return fType;
+}
+/**
+ * Returns the souce code to be used for this
+ * field's type.
+ */
+protected char[] getTypeContents() {
+       if (isTypeAltered()) {
+               return fType.toCharArray();
+       } else {
+               return CharArrayOps.subarray(fDocument, fTypeRange[0], fTypeRange[1] + 1 - fTypeRange[0]); 
+       }
+}
+/**
+ * Returns true if this field has an initializer expression,
+ * otherwise false.
+ */
+protected boolean hasInitializer() {
+       return getMask(MASK_FIELD_HAS_INITIALIZER);
+}
+/**
+ * Returns true is this field declarations has more than one
+ * variable declarator, otherwise false;
+ */
+protected boolean hasMultipleVariableDeclarators() {
+       return fNextNode != null && (fNextNode instanceof DOMField) &&
+               ((DOMField)fNextNode).isVariableDeclarator();
+}
+/**
+ * Inserts the given un-parented node as a sibling of this node, immediately before
+ * this node. Once inserted, the sibling is only dependent on this document fragment.
+ *
+ * <p>When a sibling is inserted before a variable declarator, it must first
+ * be expanded.
+ *
+ * @see IDOMNode#insertSibling(IDOMNode)
+ */
+public void insertSibling(IDOMNode sibling) throws IllegalArgumentException, DOMException {
+       if (isVariableDeclarator()) {
+               expand();
+       } 
+       super.insertSibling(sibling);
+}
+/**
+ * Returns true if this field's type has been altered
+ * from the original document contents.
+ */
+protected boolean isTypeAltered() {
+       return getMask(MASK_FIELD_TYPE_ALTERED);
+}
+/**
+ * Returns true if this field is declared as a secondary variable
+ * declarator for a previous field declaration.
+ */
+protected boolean isVariableDeclarator() {
+       return getMask(MASK_FIELD_IS_VARIABLE_DECLARATOR);
+}
+/**
+ * @see DOMNode
+ */
+protected DOMNode newDOMNode() {
+       return new DOMField();
+}
+/**
+ * Normalizes this <code>DOMNode</code>'s end position.
+ */
+void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
+       if (next == null) {
+               // this node's end position includes all of the characters up
+               // to the end of the enclosing node
+               DOMNode parent = (DOMNode) getParent();
+               if (parent == null || parent instanceof DOMCompilationUnit) {
+                       setSourceRangeEnd(fDocument.length - 1);
+               } else {
+                       // parent is a type
+                       int temp = ((DOMType)parent).getCloseBodyPosition() - 1;
+                       setSourceRangeEnd(temp);
+                       fInsertionPosition = Math.max(finder.getLineStart(temp + 1), getEndPosition());
+               }
+       } else {
+               // this node's end position is just before the start of the next node
+               // unless the next node is a field that is declared along with this one
+               int temp = next.getStartPosition() - 1;
+               fInsertionPosition = Math.max(finder.getLineStart(temp + 1), getEndPosition());
+               
+               next.normalizeStartPosition(getEndPosition(), finder);
+               if (next instanceof DOMField) {
+                       DOMField field = (DOMField) next;
+                       if (field.isVariableDeclarator() && fTypeRange[0] == field.fTypeRange[0])
+                               return;
+               }
+               setSourceRangeEnd(next.getStartPosition() - 1);
+       }
+}
+/**
+ * Normalizes this <code>DOMNode</code>'s start position.
+ */
+void normalizeStartPosition(int endPosition, ILineStartFinder finder) {
+       if (isVariableDeclarator()) {
+               // start position is end of last element
+               setStartPosition(fPreviousNode.getEndPosition() + 1);
+       } else {
+               super.normalizeStartPosition(endPosition, finder);
+       }
+}
+/**
+ * Offsets all the source indexes in this node by the given amount.
+ */
+protected void offset(int offset) {
+       super.offset(offset);
+       offsetRange(fInitializerRange, offset);
+       offsetRange(fTypeRange, offset);
+}
+/**
+ * Separates this node from its parent and siblings, maintaining any ties that
+ * this node has to the underlying document fragment.
+ *
+ * <p>When a field with multiple declarators is removed, its declaration
+ * must first be expanded.
+ *
+ * @see IDOMNode#remove()
+ */
+public void remove() {
+       expand();
+       super.remove();
+}
+/**
+ * @see IDOMMember#setComment(String)
+ */
+public void setComment(String comment) {
+       expand();
+       super.setComment(comment);
+}
+/**
+ * @see IDOMMember#setFlags(int)
+ */
+public void setFlags(int flags) {
+       expand();
+       super.setFlags(flags);
+}
+/**
+ * Sets the state of this field declaration as having
+ * an initializer expression.
+ */
+protected void setHasInitializer(boolean hasInitializer) {
+       setMask(MASK_FIELD_HAS_INITIALIZER, hasInitializer);
+}
+/**
+ * @see IDOMField#setInitializer(char[])
+ */
+public void setInitializer(String initializer) {
+       becomeDetailed();
+       fragment();
+       setHasInitializer(initializer != null);
+       fInitializer= initializer;
+}
+/**
+ * Sets the initializer range.
+ */
+void setInitializerRange(int start, int end) {
+       fInitializerRange[0] = start;
+       fInitializerRange[1] = end;
+}
+/**
+ * Sets the state of this field declaration as being a
+ * secondary variable declarator for a previous field
+ * declaration.
+ */
+protected void setIsVariableDeclarator(boolean isVariableDeclarator) {
+       setMask(MASK_FIELD_IS_VARIABLE_DECLARATOR, isVariableDeclarator);
+}
+/**
+ * @see IDOMField#setName(char[])
+ */
+public void setName(String name) throws IllegalArgumentException {
+       if (name == null) {
+               throw new IllegalArgumentException(Util.bind("element.nullName")); //$NON-NLS-1$
+       } else {
+               super.setName(name);
+               setTypeAltered(true);
+       }
+}
+/**
+ * @see IDOMField#setType(char[])
+ */
+public void setType(String typeName) throws IllegalArgumentException {
+       if (typeName == null) {
+               throw new IllegalArgumentException(Util.bind("element.nullType")); //$NON-NLS-1$
+       }
+       becomeDetailed();
+       expand();
+       fragment();
+       setTypeAltered(true);
+       setNameAltered(true);
+       fType= typeName;
+}
+/**
+ * Sets the state of this field declaration as having
+ * the field type altered from the original document.
+ */
+protected void setTypeAltered(boolean typeAltered) {
+       setMask(MASK_FIELD_TYPE_ALTERED, typeAltered);
+}
+/**
+ * @see DOMNode#shareContents(DOMNode)
+ */
+protected void shareContents(DOMNode node) {
+       super.shareContents(node);
+       DOMField field= (DOMField)node;
+       fInitializer= field.fInitializer;
+       fInitializerRange= rangeCopy(field.fInitializerRange);
+       fType= field.fType;
+       fTypeRange= rangeCopy(field.fTypeRange);
+}
+/**
+ * @see IDOMNode#toString()
+ */
+public String toString() {
+       return "FIELD: " + getName(); //$NON-NLS-1$
+}
+}