/******************************************************************************* * 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 net.sourceforge.phpdt.core.Flags; import net.sourceforge.phpdt.core.jdom.IDOMMember; import net.sourceforge.phpdt.internal.compiler.env.IConstants; import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer; import net.sourceforge.phpdt.internal.core.util.CharArrayOps; /** * DOMMember provides an implementation of IDOMMember. * * @see IDOMMember * @see DOMNode */ abstract class DOMMember extends DOMNode implements IDOMMember { /** * The modifier flags for this member that can be analyzed with * net.sourceforge.phpdt.core.Flags */ protected int fFlags = 0; /** * The member's comments when it has been altered from the contents in the * document, otherwise null. */ protected String fComment = null; /** * The original inclusive source range of the member's preceding comments in * the document, or -1's if the member did not originally have a comment. */ protected int[] fCommentRange; /** * The member's modifiers textual representation when the modifiers (flags) * have been altered from their original contents, otherwise * null. */ protected char[] fModifiers = null; /** * The original inclusive source range of the member's modifiers in the * document, or -1's if the member did not originally have modifiers in the * source code (that is, package default visibility). */ protected int[] fModifierRange; /** * Constructs an empty member node. */ DOMMember() { } /** * Creates a new member 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 node, or * null if this node does not have a name * @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 * immediately 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 net.sourceforge.phpdt.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. */ DOMMember(char[] document, int[] sourceRange, String name, int[] nameRange, int[] commentRange, int flags, int[] modifierRange) { super(document, sourceRange, name, nameRange); fFlags = flags; fComment = null; fCommentRange = commentRange; fModifierRange = modifierRange; setHasComment(commentRange[0] >= 0); } /** * Appends the contents of this node to the given CharArrayBuffer, using the * original document and indicies as a form for the current attribute values * of this node. * *

* To facilitate the implementation of generating contents for members, the * content of members is split into three sections - the header, * declaration, and body sections. The header section includes any preceding * comments and modifiers. The declaration section includes the portion of * the member declaration that follows any modifiers and precedes the member * body. The body section includes the member body and any trailing * whitespace. * * @see DOMNode#appendFragmentedContents(CharArrayBuffer) */ protected void appendFragmentedContents(CharArrayBuffer buffer) { if (isDetailed()) { appendMemberHeaderFragment(buffer); appendMemberDeclarationContents(buffer); appendMemberBodyContents(buffer); } else { appendSimpleContents(buffer); } } /** * Appends this member's body contents to the given CharArrayBuffer. Body * contents include the member body and any trailing whitespace. */ protected abstract void appendMemberBodyContents(CharArrayBuffer buffer); /** * Appends this member's declaration contents to the given CharArrayBuffer. * The declaration contents includes the portion of this member that appears * after any modifiers and precedes the body. */ protected abstract void appendMemberDeclarationContents( CharArrayBuffer buffer); /** * Appends this member's header contents to the given CharArrayBuffer. * Header contents include any preceding comments and modifiers. */ protected void appendMemberHeaderFragment(CharArrayBuffer buffer) { int spaceStart, spaceEnd; // space before comment if (hasComment()) { spaceStart = fSourceRange[0]; spaceEnd = fCommentRange[0]; if (spaceEnd > 0) { buffer.append(fDocument, spaceStart, spaceEnd - spaceStart); } } String fragment = getComment(); if (fragment != null) { buffer.append(fragment); } if (fCommentRange[1] >= 0) { spaceStart = fCommentRange[1] + 1; } else { spaceStart = fSourceRange[0]; } if (fModifierRange[0] >= 0) { spaceEnd = fModifierRange[0] - 1; } else { spaceEnd = getMemberDeclarationStartPosition() - 1; } if (spaceEnd >= spaceStart) { buffer.append(fDocument, spaceStart, spaceEnd + 1 - spaceStart); } buffer.append(getModifiersText()); } /** * Appends the contents of this node to the given CharArrayBuffer, using the * original document and indicies as a form for the current attribute values * of this node. This method is called when this node is know not to have * detailed source indexes. */ protected abstract void appendSimpleContents(CharArrayBuffer buffer); /** * Returns a copy of the given array with the new element appended to the * end of the array. */ protected String[] appendString(String[] list, String element) { String[] copy = new String[list.length + 1]; System.arraycopy(list, 0, copy, 0, list.length); copy[list.length] = element; return copy; } /** * Returns a String describing the modifiers for this member, * ending with whitespace (if not empty). This value serves as a replacement * value for the member's modifier range when the modifiers have been * altered from their original contents. */ protected char[] generateFlags() { char[] flags = Flags.toString(getFlags()).toCharArray(); if (flags.length == 0) { return flags; } else { return CharArrayOps.concat(flags, new char[] { ' ' }); } } /** * @see IDOMMember#getComment() */ public String getComment() { becomeDetailed(); if (hasComment()) { if (fComment != null) { return fComment; } else { return CharArrayOps.substring(fDocument, fCommentRange[0], fCommentRange[1] + 1 - fCommentRange[0]); } } else { return null; } } /** * @see IDOMMember#getFlags() */ public int getFlags() { return fFlags; } /** * Returns the location of the first character in the member's declaration * section. * * @see DOMMember#getMemberDeclarationContents() * @see DOMMember#getFragmentedContents() */ protected abstract int getMemberDeclarationStartPosition(); /** * Returns the String to be used for this member's flags when generating * contents - either the original contents in the document or the * replacement value. */ protected char[] getModifiersText() { if (fModifiers == null) { if (fModifierRange[0] < 0) { return null; } else { return CharArrayOps.subarray(fDocument, fModifierRange[0], fModifierRange[1] + 1 - fModifierRange[0]); } } else { return fModifiers; } } /** * Returns true if this member currently has a body. */ protected boolean hasBody() { return getMask(MASK_HAS_BODY); } /** * Returns true if this member currently has a comment. */ protected boolean hasComment() { return getMask(MASK_HAS_COMMENT); } /** * Offsets all the source indexes in this node by the given amount. */ protected void offset(int offset) { super.offset(offset); offsetRange(fCommentRange, offset); offsetRange(fModifierRange, offset); } /** * @see IDOMMember#setComment(String) */ public void setComment(String comment) { becomeDetailed(); fComment = comment; fragment(); setHasComment(comment != null); /* see 1FVIJAH */ if (comment != null) { String commentString = new String(comment); if (commentString.indexOf("@deprecated") >= 0) { //$NON-NLS-1$ fFlags = fFlags | IConstants.AccDeprecated; return; } } fFlags = fFlags & (~IConstants.AccDeprecated); } /** * @see IDOMMember#setFlags(int) */ public void setFlags(int flags) { becomeDetailed(); if (Flags.isDeprecated(fFlags)) { fFlags = flags | IConstants.AccDeprecated; } else { fFlags = flags & (~IConstants.AccDeprecated); } fragment(); fModifiers = generateFlags(); } /** * Sets the state of this member declaration as having a body. */ protected void setHasBody(boolean hasBody) { setMask(MASK_HAS_BODY, hasBody); } /** * Sets the state of this member declaration as having a preceding comment. */ protected void setHasComment(boolean hasComment) { setMask(MASK_HAS_COMMENT, hasComment); } /** * Sets the original position of the first character of this node's contents * in its document. This method is only used during DOM creation while * normalizing the source range of each node. * * Synchronize the start of the comment position with the start of the node. */ protected void setStartPosition(int start) { if (fCommentRange[0] >= 0) { fCommentRange[0] = start; } super.setStartPosition(start); } /** * @see DOMNode#shareContents(DOMNode) */ protected void shareContents(DOMNode node) { super.shareContents(node); DOMMember member = (DOMMember) node; fComment = member.fComment; fCommentRange = rangeCopy(member.fCommentRange); fFlags = member.fFlags; fModifiers = member.fModifiers; fModifierRange = rangeCopy(member.fModifierRange); } }