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 net.sourceforge.phpdt.core.IJavaElement;
14 import net.sourceforge.phpdt.core.IType;
15 import net.sourceforge.phpdt.core.Signature;
16 import net.sourceforge.phpdt.core.jdom.IDOMMethod;
17 import net.sourceforge.phpdt.core.jdom.IDOMNode;
18 import net.sourceforge.phpdt.internal.compiler.util.Util;
19 import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
20 import net.sourceforge.phpdt.internal.core.util.CharArrayOps;
23 * DOMMethod provides an implementation of IDOMMethod.
29 class DOMMethod extends DOMMember implements IDOMMethod {
32 * Contains the return type of the method when the return type has been
33 * altered from the contents in the document, otherwise <code>null</code>.
35 protected String fReturnType;
38 * The original inclusive source range of the method's return type in the
39 * document, or -1's if no return type is present in the document. If the
40 * return type of this method is qualified with '[]' following the parameter
41 * list, this array has four entries. In this case, the last two entries of
42 * the array are the inclusive source range of the array qualifiers.
44 protected int[] fReturnTypeRange;
47 * Contains the textual representation of the method's parameter list,
48 * including open and closing parentheses when the parameters had been
49 * altered from the contents in the document, otherwise <code>null</code>.
51 protected char[] fParameterList;
54 * The original inclusive source range of the method's parameter list in the
57 protected int[] fParameterRange;
60 * Contains the textual representation of the method's exception list when
61 * the exceptions had been altered from the contents in the document,
62 * otherwise <code>null</code>. The exception list is a comment delimited
63 * list of exceptions, not including the "throws" keyword.
65 protected char[] fExceptionList;
68 * The original inclusive source range of the method's exception list in the
71 protected int[] fExceptionRange;
74 * Contains the method's body when the body has been altered from the
75 * contents in the document, otherwise <code>null</code>. The body
76 * includes everything between and including the enclosing braces, and
77 * trailing whitespace.
79 protected String fBody;
82 * The original inclusive source range of the method's body.
84 protected int[] fBodyRange;
87 * Names of parameters in the method parameter list, or <code>null</code>
88 * if the method has no parameters.
90 protected String[] fParameterNames;
93 * Types of parameters in the method parameter list, or <code>null</code>
94 * if the method has no parameters.
96 protected String[] fParameterTypes;
99 * The exceptions the method throws, or <code>null</code> if the method
100 * throws no exceptions.
102 protected String[] fExceptions;
105 * Constructs an empty method node.
112 * Creates a new detailed METHOD document fragment on the given range of the
116 * the document containing this node's original contents
117 * @param sourceRange -
118 * a two element array of integers describing the entire
119 * inclusive source range of this node within its document.
120 * Contents start on and include the character at the first
121 * position. Contents end on and include the character at the
122 * last position. An array of -1's indicates this node's contents
123 * do not exist in the document.
125 * the identifier portion of the name of this node, or
126 * <code>null</code> if this node does not have a name
128 * a two element array of integers describing the entire
129 * inclusive source range of this node's name within its
130 * document, including any array qualifiers that might
131 * immediately follow the name or -1's if this node does not have
133 * @param commentRange -
134 * a two element array describing the comments that precede the
135 * member declaration. The first matches the start of this node's
136 * sourceRange, and the second is the new-line or first
137 * non-whitespace character following the last comment. If no
138 * comments are present, this array contains two -1's.
140 * an integer representing the modifiers for this member. The
141 * integer can be analyzed with net.sourceforge.phpdt.core.Flags
142 * @param modifierRange -
143 * a two element array describing the location of modifiers for
144 * this member within its source range. The first integer is the
145 * first character of the first modifier for this member, and the
146 * second integer is the last whitespace character preceeding the
147 * next part of this member declaration. If there are no
148 * modifiers present in this node's source code (that is, package
149 * default visibility), this array contains two -1's.
150 * @param isConstructor -
151 * true if the method is a contructor, otherwise false
152 * @param returnType -
153 * the normalized return type of this method
154 * @param returnTypeRange -
155 * a two element array describing the location of the return type
156 * within the method's source range. The first integer is is the
157 * position of the first character in the return type, and the
158 * second integer is the position of the last character in the
159 * return type. For constructors, the contents of this array are
160 * -1's. If the return type of this method is qualified with '[]'
161 * following the parameter list, this array has four entries. In
162 * this case, the last two entries of the array are the inclusive
163 * source range of the array qualifiers.
164 * @param parameterTypes -
165 * an array of parameter types in the method declaration or
166 * <code>null</code> if the method has no parameters
167 * @param parameterNames -
168 * an array of parameter names in the method declaration or
169 * <code>null</code> if the method has no parameters
170 * @param parameterRange -
171 * a two element array describing the location of the parameter
172 * list in the method. The first integer is the location of the
173 * open parenthesis and the second integer is the location of the
174 * closing parenthesis.
175 * @param exceptions -
176 * an array of the names of exceptions thrown by this method or
177 * <code>null</code> if the method throws no exceptions
178 * @param exceptionRange -
179 * a two element array describing the location of the exception
180 * list in the method declaration. The first integer is the
181 * position of the first character in the first exception the
182 * method throws, and the second integer is the position of the
183 * last character of the last exception this method throws.
185 * a two element array describing the location of the method's
186 * body. The first integer is the first character following the
187 * method's parameter list, or exception list (if present). The
188 * second integer is the location of the last character in the
189 * method's source range.
191 DOMMethod(char[] document, int[] sourceRange, String name, int[] nameRange,
192 int[] commentRange, int flags, int[] modifierRange,
193 boolean isConstructor, String returnType, int[] returnTypeRange,
194 String[] parameterTypes, String[] parameterNames,
195 int[] parameterRange, String[] exceptions, int[] exceptionRange,
197 super(document, sourceRange, name, nameRange, commentRange, flags,
200 setMask(MASK_IS_CONSTRUCTOR, isConstructor);
201 fReturnType = returnType;
202 fReturnTypeRange = returnTypeRange;
203 fParameterTypes = parameterTypes;
204 fParameterNames = parameterNames;
205 fParameterRange = parameterRange;
206 fExceptionRange = exceptionRange;
207 fExceptions = exceptions;
209 fBodyRange = bodyRange;
210 setMask(MASK_DETAILED_SOURCE_INDEXES, true);
215 * Creates a new simple METHOD document fragment on the given range of the
219 * the document containing this node's original contents
220 * @param sourceRange -
221 * a two element array of integers describing the entire
222 * inclusive source range of this node within its document.
223 * Contents start on and include the character at the first
224 * position. Contents end on and include the character at the
225 * last position. An array of -1's indicates this node's contents
226 * do not exist in the document.
228 * the identifier portion of the name of this node, or
229 * <code>null</code> if this node does not have a name
231 * a two element array of integers describing the entire
232 * inclusive source range of this node's name within its
233 * document, including any array qualifiers that might
234 * immediately follow the name or -1's if this node does not have
237 * an integer representing the modifiers for this member. The
238 * integer can be analyzed with net.sourceforge.phpdt.core.Flags
239 * @param isConstructor -
240 * true if the method is a contructor, otherwise false
241 * @param returnType -
242 * the normalized return type of this method
243 * @param parameterTypes -
244 * an array of parameter types in the method declaration or
245 * <code>null</code> if the method has no parameters
246 * @param parameterNames -
247 * an array of parameter names in the method declaration or
248 * <code>null</code> if the method has no parameters
249 * @param exceptions -
250 * an array of the names of exceptions thrown by this method or
251 * <code>null</code> if the method throws no exceptions
253 DOMMethod(char[] document, int[] sourceRange, String name, int[] nameRange,
254 int flags, boolean isConstructor, String returnType,
255 String[] parameterTypes, String[] parameterNames,
256 String[] exceptions) {
257 this(document, sourceRange, name, nameRange, new int[] { -1, -1 },
258 flags, new int[] { -1, -1 }, isConstructor, returnType,
259 new int[] { -1, -1 }, parameterTypes, parameterNames,
260 new int[] { -1, -1 }, exceptions, new int[] { -1, -1 },
261 new int[] { -1, -1 });
262 setMask(MASK_DETAILED_SOURCE_INDEXES, false);
266 * @see IDOMMethod#addException(String)
268 public void addException(String name) throws IllegalArgumentException {
270 throw new IllegalArgumentException(Util
271 .bind("dom.nullExceptionType")); //$NON-NLS-1$
273 if (fExceptions == null) {
274 fExceptions = new String[1];
275 fExceptions[0] = name;
277 fExceptions = appendString(fExceptions, name);
279 setExceptions(fExceptions);
283 * @see IDOMMethod#addParameter(String, String)
285 public void addParameter(String type, String name)
286 throws IllegalArgumentException {
288 throw new IllegalArgumentException(Util
289 .bind("dom.nullTypeParameter")); //$NON-NLS-1$
292 throw new IllegalArgumentException(Util
293 .bind("dom.nullNameParameter")); //$NON-NLS-1$
295 if (fParameterNames == null) {
296 fParameterNames = new String[1];
297 fParameterNames[0] = name;
299 fParameterNames = appendString(fParameterNames, name);
301 if (fParameterTypes == null) {
302 fParameterTypes = new String[1];
303 fParameterTypes[0] = type;
305 fParameterTypes = appendString(fParameterTypes, type);
307 setParameters(fParameterTypes, fParameterNames);
311 * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
313 protected void appendMemberBodyContents(CharArrayBuffer buffer) {
315 buffer.append(fBody);
317 buffer.append(fDocument, fBodyRange[0], fBodyRange[1] + 1
323 * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
325 protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
327 if (isConstructor()) {
328 buffer.append(getConstructorName()).append(fDocument,
329 fNameRange[1] + 1, fParameterRange[0] - fNameRange[1] - 1);
331 buffer.append(getReturnTypeContents());
332 if (fReturnTypeRange[0] >= 0) {
333 buffer.append(fDocument, fReturnTypeRange[1] + 1, fNameRange[0]
334 - fReturnTypeRange[1] - 1);
338 buffer.append(getNameContents()).append(fDocument,
339 fNameRange[1] + 1, fParameterRange[0] - fNameRange[1] - 1);
341 if (fParameterList != null) {
342 buffer.append(fParameterList);
344 buffer.append(fDocument, fParameterRange[0], fParameterRange[1] + 1
345 - fParameterRange[0]);
348 if (hasTrailingArrayQualifier() && isReturnTypeAltered()) {
349 start = fReturnTypeRange[3] + 1;
351 start = fParameterRange[1] + 1;
353 if (fExceptions != null) {
354 // add 'throws' keyword
355 if (fExceptionRange[0] >= 0) {
356 buffer.append(fDocument, start, fExceptionRange[0] - start);
358 buffer.append(" throws "); //$NON-NLS-1$
360 // add exception list
361 if (fExceptionList != null) {
362 buffer.append(fExceptionList);
363 // add space before body
364 if (fExceptionRange[0] >= 0) {
365 buffer.append(fDocument, fExceptionRange[1] + 1,
366 fBodyRange[0] - fExceptionRange[1] - 1);
368 buffer.append(fDocument, fParameterRange[1] + 1,
369 fBodyRange[0] - fParameterRange[1] - 1);
372 // add list and space before body
373 buffer.append(fDocument, fExceptionRange[0], fBodyRange[0]
374 - fExceptionRange[0]);
377 // add space before body
378 if (fExceptionRange[0] >= 0) {
379 buffer.append(fDocument, fExceptionRange[1] + 1, fBodyRange[0]
380 - fExceptionRange[1] - 1);
382 buffer.append(fDocument, start, fBodyRange[0] - start);
389 * @see DOMNode#appendSimpleContents(CharArrayBuffer)
391 protected void appendSimpleContents(CharArrayBuffer buffer) {
392 // append eveything before my name
393 buffer.append(fDocument, fSourceRange[0], fNameRange[0]
396 if (isConstructor()) {
397 buffer.append(getConstructorName());
399 buffer.append(fName);
401 // append everything after my name
402 buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1]
407 * @see IDOMMethod#getBody()
409 public String getBody() {
415 return CharArrayOps.substring(fDocument, fBodyRange[0],
416 fBodyRange[1] + 1 - fBodyRange[0]);
424 * Returns the simple name of the enclsoing type for this constructor. If
425 * the constuctor is not currently enclosed in a type, the original name of
426 * the constructor as found in the documnent is returned.
428 protected String getConstructorName() {
430 if (isConstructor()) {
431 if (getParent() != null) {
432 return getParent().getName();
434 // If there is no parent use the original name
435 return new String(getNameContents());
444 * @see DOMNode#getDetailedNode()
446 // protected DOMNode getDetailedNode() {
447 // return (DOMNode)getFactory().createMethod(getContents());
450 * @see IDOMMethod#getExceptions()
452 public String[] getExceptions() {
457 * @see IDOMNode#getJavaElement
459 public IJavaElement getJavaElement(IJavaElement parent)
460 throws IllegalArgumentException {
461 if (parent.getElementType() == IJavaElement.TYPE) {
462 // translate parameter types to signatures
463 String[] sigs = null;
464 if (fParameterTypes != null) {
465 sigs = new String[fParameterTypes.length];
467 for (i = 0; i < fParameterTypes.length; i++) {
468 sigs[i] = Signature.createTypeSignature(fParameterTypes[i]
469 .toCharArray(), false);
473 if (isConstructor()) {
474 name = getConstructorName();
478 return ((IType) parent).getMethod(name, sigs);
480 throw new IllegalArgumentException(Util
481 .bind("element.illegalParent")); //$NON-NLS-1$
486 * @see DOMMember#getMemberDeclarationStartPosition()
488 protected int getMemberDeclarationStartPosition() {
489 if (fReturnTypeRange[0] >= 0) {
490 return fReturnTypeRange[0];
492 return fNameRange[0];
497 * @see IDOMNode#getName()
499 public String getName() {
500 if (isConstructor()) {
503 return super.getName();
508 * @see IDOMNode#getNodeType()
510 public int getNodeType() {
511 return IDOMNode.METHOD;
515 * @see IDOMMethod#getParameterNames()
517 public String[] getParameterNames() {
518 return fParameterNames;
522 * @see IDOMMethod#getParameterTypes()
524 public String[] getParameterTypes() {
525 return fParameterTypes;
529 * @see IDOMMethod#getReturnType()
531 public String getReturnType() {
532 if (isConstructor()) {
540 * Returns the source code to be used for this method's return type
542 protected char[] getReturnTypeContents() {
543 if (isConstructor()) {
546 if (isReturnTypeAltered()) {
547 return fReturnType.toCharArray();
549 return CharArrayOps.subarray(fDocument, fReturnTypeRange[0],
550 fReturnTypeRange[1] + 1 - fReturnTypeRange[0]);
557 * Returns true if this method's return type has array qualifiers ('[]')
558 * following the parameter list.
560 protected boolean hasTrailingArrayQualifier() {
561 return fReturnTypeRange.length > 2;
565 * @see IDOMMethod#isConstructor()
567 public boolean isConstructor() {
568 return getMask(MASK_IS_CONSTRUCTOR);
572 * Returns true if this method's return type has been altered from the
573 * original document contents.
575 protected boolean isReturnTypeAltered() {
576 return getMask(MASK_RETURN_TYPE_ALTERED);
580 * @see IDOMNode#isSigantureEqual(IDOMNode).
583 * Two methods have equal signatures if there names are the same and their
584 * parameter types are the same.
586 public boolean isSignatureEqual(IDOMNode node) {
587 boolean ok = node.getNodeType() == getNodeType();
589 IDOMMethod method = (IDOMMethod) node;
590 ok = (isConstructor() && method.isConstructor())
591 || (!isConstructor() && !method.isConstructor());
592 if (ok && !isConstructor()) {
593 ok = getName().equals(method.getName());
599 String[] types = method.getParameterTypes();
600 if (fParameterTypes == null || fParameterTypes.length == 0) {
601 // this method has no parameters
602 if (types == null || types.length == 0) {
603 // the other method has no parameters either
607 // this method has parameters
608 if (types == null || types.length == 0) {
609 // the other method has no parameters
612 if (fParameterTypes.length != types.length) {
613 // the methods have a different number of parameters
617 for (i = 0; i < types.length; i++) {
618 if (!fParameterTypes[i].equals(types[i])) {
632 protected DOMNode newDOMNode() {
633 return new DOMMethod();
637 * Offsets all the source indexes in this node by the given amount.
639 protected void offset(int offset) {
640 super.offset(offset);
641 offsetRange(fBodyRange, offset);
642 offsetRange(fExceptionRange, offset);
643 offsetRange(fParameterRange, offset);
644 offsetRange(fReturnTypeRange, offset);
648 * @see IDOMMethod#setBody
650 public void setBody(String body) {
654 setHasBody(body != null);
656 fBody = ";" + Util.LINE_SEPARATOR; //$NON-NLS-1$
661 * Sets the end of the body range
663 void setBodyRangeEnd(int end) {
668 * @see IDOMMethod#setConstructor(boolean)
670 public void setConstructor(boolean b) {
672 setMask(MASK_IS_CONSTRUCTOR, b);
677 * @see IDOMMethod#setExceptions(char[][])
679 public void setExceptions(String[] names) {
681 if (names == null || names.length == 0) {
685 CharArrayBuffer buffer = new CharArrayBuffer();
686 char[] comma = new char[] { ',', ' ' };
687 for (int i = 0, length = names.length; i < length; i++) {
689 buffer.append(comma);
690 buffer.append(names[i]);
692 fExceptionList = buffer.getContents();
698 * @see IDOMMethod#setName
700 public void setName(String name) {
702 throw new IllegalArgumentException(Util.bind("element.nullName")); //$NON-NLS-1$
709 * @see IDOMMethod#setParameters(char[][], char[][])
711 public void setParameters(String[] types, String[] names)
712 throws IllegalArgumentException {
714 if (types == null || names == null) {
715 if (types == null && names == null) {
716 fParameterTypes = null;
717 fParameterNames = null;
718 fParameterList = new char[] { '(', ')' };
720 throw new IllegalArgumentException(Util
721 .bind("dom.mismatchArgNamesAndTypes")); //$NON-NLS-1$
723 } else if (names.length != types.length) {
724 throw new IllegalArgumentException(Util
725 .bind("dom.mismatchArgNamesAndTypes")); //$NON-NLS-1$
726 } else if (names.length == 0) {
727 setParameters(null, null);
729 fParameterNames = names;
730 fParameterTypes = types;
731 CharArrayBuffer parametersBuffer = new CharArrayBuffer();
732 parametersBuffer.append("("); //$NON-NLS-1$
733 char[] comma = new char[] { ',', ' ' };
734 for (int i = 0; i < names.length; i++) {
736 parametersBuffer.append(comma);
738 parametersBuffer.append(types[i]).append(' ').append(names[i]);
740 parametersBuffer.append(')');
741 fParameterList = parametersBuffer.getContents();
747 * @see IDOMMethod#setReturnType(char[])
749 public void setReturnType(String name) throws IllegalArgumentException {
751 throw new IllegalArgumentException(Util.bind("dom.nullReturnType")); //$NON-NLS-1$
755 setReturnTypeAltered(true);
760 * Sets the state of this method declaration as having the return type
761 * altered from the original document.
763 protected void setReturnTypeAltered(boolean typeAltered) {
764 setMask(MASK_RETURN_TYPE_ALTERED, typeAltered);
769 protected void setSourceRangeEnd(int end) {
770 super.setSourceRangeEnd(end);
775 * @see DOMNode#shareContents(DOMNode)
777 protected void shareContents(DOMNode node) {
778 super.shareContents(node);
779 DOMMethod method = (DOMMethod) node;
780 fBody = method.fBody;
781 fBodyRange = rangeCopy(method.fBodyRange);
782 fExceptionList = method.fExceptionList;
783 fExceptionRange = rangeCopy(method.fExceptionRange);
784 fExceptions = method.fExceptions;
785 fParameterList = method.fParameterList;
786 fParameterNames = method.fParameterNames;
787 fParameterRange = rangeCopy(method.fParameterRange);
788 fParameterTypes = method.fParameterTypes;
789 fReturnType = method.fReturnType;
790 fReturnTypeRange = rangeCopy(method.fReturnTypeRange);
794 * @see IDOMNode#toString()
796 public String toString() {
797 if (isConstructor()) {
798 return "CONSTRUCTOR"; //$NON-NLS-1$
800 return "METHOD: " + getName(); //$NON-NLS-1$