/******************************************************************************* * 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); } }