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
33 * return type has been altered from the contents
34 * in the document, otherwise <code>null</code>.
36 protected String fReturnType;
39 * The original inclusive source range of the
40 * method's return type in the document, or -1's
41 * if no return type is present in the document.
42 * If the return type of this method is qualified with
43 * '[]' following the parameter list, this array has
44 * four entries. In this case, the last two entries
45 * of the array are the inclusive source range of
46 * the array qualifiers.
48 protected int[] fReturnTypeRange;
51 * Contains the textual representation of the method's
52 * parameter list, including open and closing parentheses
53 * when the parameters had been altered from the contents
54 * in the document, otherwise <code>null</code>.
56 protected char[] fParameterList;
59 * The original inclusive source range of the
60 * method's parameter list in the document.
62 protected int[] fParameterRange;
65 * Contains the textual representation of the method's
66 * exception list when the exceptions had been altered
67 * from the contents in the document, otherwise
68 * <code>null</code>. The exception list is a comment
69 * delimited list of exceptions, not including the "throws"
72 protected char[] fExceptionList;
75 * The original inclusive source range of the
76 * method's exception list in the document.
78 protected int[] fExceptionRange;
81 * Contains the method's body when the body has
82 * been altered from the contents in the document,
83 * otherwise <code>null</code>. The body includes everything
84 * between and including the enclosing braces, and trailing
87 protected String fBody;
90 * The original inclusive source range of the
93 protected int[] fBodyRange;
97 * Names of parameters in the method parameter list,
98 * or <code>null</code> if the method has no parameters.
100 protected String[] fParameterNames;
103 * Types of parameters in the method parameter list,
104 * or <code>null</code> if the method has no parameters.
106 protected String[] fParameterTypes;
109 * The exceptions the method throws, or <code>null</code>
110 * if the method throws no exceptions.
112 protected String[] fExceptions;
116 * Constructs an empty method node.
122 * Creates a new detailed METHOD document fragment on the given range of the document.
124 * @param document - the document containing this node's original contents
125 * @param sourceRange - a two element array of integers describing the
126 * entire inclusive source range of this node within its document.
127 * Contents start on and include the character at the first position.
128 * Contents end on and include the character at the last position.
129 * An array of -1's indicates this node's contents do not exist
131 * @param name - the identifier portion of the name of this node, or
132 * <code>null</code> if this node does not have a name
133 * @param nameRange - a two element array of integers describing the
134 * entire inclusive source range of this node's name within its document,
135 * including any array qualifiers that might immediately follow the name
136 * or -1's if this node does not have a name.
137 * @param commentRange - a two element array describing the comments that precede
138 * the member declaration. The first matches the start of this node's
139 * sourceRange, and the second is the new-line or first non-whitespace
140 * character following the last comment. If no comments are present,
141 * this array contains two -1's.
142 * @param flags - an integer representing the modifiers for this member. The
143 * integer can be analyzed with org.eclipse.jdt.core.Flags
144 * @param modifierRange - a two element array describing the location of
145 * modifiers for this member within its source range. The first integer
146 * is the first character of the first modifier for this member, and
147 * the second integer is the last whitespace character preceeding the
148 * next part of this member declaration. If there are no modifiers present
149 * in this node's source code (that is, package default visibility), this array
151 * @param isConstructor - true if the method is a contructor, otherwise false
152 * @param returnType - the normalized return type of this method
153 * @param returnTypeRange - a two element array describing the location of the
154 * return type within the method's source range. The first integer is is
155 * the position of the first character in the return type, and the second
156 * integer is the position of the last character in the return type.
157 * For constructors, the contents of this array are -1's.
158 * If the return type of this method is qualified with '[]' following the
159 * parameter list, this array has four entries. In this case, the last
160 * two entries of the array are the inclusive source range of the array
162 * @param parameterTypes - an array of parameter types in the method declaration
163 * or <code>null</code> if the method has no parameters
164 * @param parameterNames - an array of parameter names in the method declaration
165 * or <code>null</code> if the method has no parameters
166 * @param parameterRange - a two element array describing the location of the
167 * parameter list in the method. The first integer is the location of the
168 * open parenthesis and the second integer is the location of the closing
170 * @param exceptions - an array of the names of exceptions thrown by this method
171 * or <code>null</code> if the method throws no exceptions
172 * @param exceptionRange - a two element array describing the location of the
173 * exception list in the method declaration. The first integer is the position
174 * of the first character in the first exception the method throws, and the
175 * second integer is the position of the last character of the last exception
176 * this method throws.
177 * @param bodyRange - a two element array describing the location of the method's body.
178 * The first integer is the first character following the method's
179 * parameter list, or exception list (if present). The second integer is the location
180 * of the last character in the method's source range.
182 DOMMethod(char[] document, int[] sourceRange, String name, int[] nameRange, int[] commentRange, int flags, int[] modifierRange, boolean isConstructor, String returnType, int[] returnTypeRange, String[] parameterTypes, String[] parameterNames, int[] parameterRange, String[] exceptions, int[] exceptionRange, int[] bodyRange) {
183 super(document, sourceRange, name, nameRange, commentRange, flags, modifierRange);
185 setMask(MASK_IS_CONSTRUCTOR, isConstructor);
186 fReturnType= returnType;
187 fReturnTypeRange= returnTypeRange;
188 fParameterTypes= parameterTypes;
189 fParameterNames= parameterNames;
190 fParameterRange= parameterRange;
191 fExceptionRange= exceptionRange;
192 fExceptions= exceptions;
194 fBodyRange= bodyRange;
195 setMask(MASK_DETAILED_SOURCE_INDEXES, true);
199 * Creates a new simple METHOD document fragment on the given range of the document.
201 * @param document - the document containing this node's original contents
202 * @param sourceRange - a two element array of integers describing the
203 * entire inclusive source range of this node within its document.
204 * Contents start on and include the character at the first position.
205 * Contents end on and include the character at the last position.
206 * An array of -1's indicates this node's contents do not exist
208 * @param name - the identifier portion of the name of this node, or
209 * <code>null</code> if this node does not have a name
210 * @param nameRange - a two element array of integers describing the
211 * entire inclusive source range of this node's name within its document,
212 * including any array qualifiers that might immediately follow the name
213 * or -1's if this node does not have a name.
214 * @param flags - an integer representing the modifiers for this member. The
215 * integer can be analyzed with org.eclipse.jdt.core.Flags
216 * @param isConstructor - true if the method is a contructor, otherwise false
217 * @param returnType - the normalized return type of this method
218 * @param parameterTypes - an array of parameter types in the method declaration
219 * or <code>null</code> if the method has no parameters
220 * @param parameterNames - an array of parameter names in the method declaration
221 * or <code>null</code> if the method has no parameters
222 * @param exceptions - an array of the names of exceptions thrown by this method
223 * or <code>null</code> if the method throws no exceptions
225 DOMMethod(char[] document, int[] sourceRange, String name, int[] nameRange, int flags, boolean isConstructor, String returnType, String[] parameterTypes, String[] parameterNames, String[] exceptions) {
226 this(document, sourceRange, name, nameRange, new int[] {-1, -1}, flags, new int[] {-1, -1}, isConstructor, returnType, new int[] {-1, -1}, parameterTypes, parameterNames, new int[] {-1, -1}, exceptions, new int[] {-1, -1}, new int[] {-1, -1});
227 setMask(MASK_DETAILED_SOURCE_INDEXES, false);
230 * @see IDOMMethod#addException(String)
232 public void addException(String name) throws IllegalArgumentException {
234 throw new IllegalArgumentException(Util.bind("dom.nullExceptionType")); //$NON-NLS-1$
236 if (fExceptions == null) {
237 fExceptions= new String[1];
238 fExceptions[0]= name;
240 fExceptions= appendString(fExceptions, name);
242 setExceptions(fExceptions);
245 * @see IDOMMethod#addParameter(String, String)
247 public void addParameter(String type, String name) throws IllegalArgumentException {
249 throw new IllegalArgumentException(Util.bind("dom.nullTypeParameter")); //$NON-NLS-1$
252 throw new IllegalArgumentException(Util.bind("dom.nullNameParameter")); //$NON-NLS-1$
254 if (fParameterNames == null) {
255 fParameterNames= new String[1];
256 fParameterNames[0]= name;
258 fParameterNames= appendString(fParameterNames, name);
260 if (fParameterTypes == null) {
261 fParameterTypes= new String[1];
262 fParameterTypes[0]= type;
264 fParameterTypes= appendString(fParameterTypes, type);
266 setParameters(fParameterTypes, fParameterNames);
269 * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
271 protected void appendMemberBodyContents(CharArrayBuffer buffer) {
273 buffer.append(fBody);
275 buffer.append(fDocument, fBodyRange[0], fBodyRange[1] + 1 - fBodyRange[0]);
279 * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer)
281 protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
283 if (isConstructor()) {
285 .append(getConstructorName())
286 .append(fDocument, fNameRange[1] + 1, fParameterRange[0] - fNameRange[1] - 1);
288 buffer.append(getReturnTypeContents());
289 if (fReturnTypeRange[0] >= 0) {
290 buffer.append(fDocument, fReturnTypeRange[1] + 1, fNameRange[0] - fReturnTypeRange[1] - 1);
295 .append(getNameContents())
296 .append(fDocument, fNameRange[1] + 1, fParameterRange[0] - fNameRange[1] - 1);
298 if (fParameterList != null) {
299 buffer.append(fParameterList);
301 buffer.append(fDocument, fParameterRange[0], fParameterRange[1] + 1 - fParameterRange[0]);
304 if (hasTrailingArrayQualifier() && isReturnTypeAltered()) {
305 start= fReturnTypeRange[3] + 1;
307 start= fParameterRange[1] + 1;
309 if (fExceptions != null) {
310 // add 'throws' keyword
311 if (fExceptionRange[0] >= 0) {
312 buffer.append(fDocument, start, fExceptionRange[0] - start);
314 buffer.append(" throws "); //$NON-NLS-1$
316 // add exception list
317 if (fExceptionList != null) {
318 buffer.append(fExceptionList);
319 // add space before body
320 if (fExceptionRange[0] >= 0) {
321 buffer.append(fDocument, fExceptionRange[1] + 1, fBodyRange[0] - fExceptionRange[1] - 1);
323 buffer.append(fDocument, fParameterRange[1] + 1, fBodyRange[0] - fParameterRange[1] - 1);
326 // add list and space before body
327 buffer.append(fDocument, fExceptionRange[0], fBodyRange[0] - fExceptionRange[0]);
330 // add space before body
331 if (fExceptionRange[0] >= 0) {
332 buffer.append(fDocument, fExceptionRange[1] + 1, fBodyRange[0] - fExceptionRange[1] - 1);
334 buffer.append(fDocument, start, fBodyRange[0] - start);
340 * @see DOMNode#appendSimpleContents(CharArrayBuffer)
342 protected void appendSimpleContents(CharArrayBuffer buffer) {
343 // append eveything before my name
344 buffer.append(fDocument, fSourceRange[0], fNameRange[0] - fSourceRange[0]);
346 if (isConstructor()) {
347 buffer.append(getConstructorName());
349 buffer.append(fName);
351 // append everything after my name
352 buffer.append(fDocument, fNameRange[1] + 1, fSourceRange[1] - fNameRange[1]);
355 * @see IDOMMethod#getBody()
357 public String getBody() {
363 return CharArrayOps.substring(fDocument, fBodyRange[0], fBodyRange[1] + 1 - fBodyRange[0]);
370 * Returns the simple name of the enclsoing type for this constructor.
371 * If the constuctor is not currently enclosed in a type, the original
372 * name of the constructor as found in the documnent is returned.
374 protected String getConstructorName() {
376 if (isConstructor()) {
377 if (getParent() != null) {
378 return getParent().getName();
380 // If there is no parent use the original name
381 return new String(getNameContents());
389 * @see DOMNode#getDetailedNode()
391 //protected DOMNode getDetailedNode() {
392 // return (DOMNode)getFactory().createMethod(getContents());
395 * @see IDOMMethod#getExceptions()
397 public String[] getExceptions() {
401 * @see IDOMNode#getJavaElement
403 public IJavaElement getJavaElement(IJavaElement parent) throws IllegalArgumentException {
404 if (parent.getElementType() == IJavaElement.TYPE) {
405 // translate parameter types to signatures
407 if (fParameterTypes != null) {
408 sigs= new String[fParameterTypes.length];
410 for (i= 0; i < fParameterTypes.length; i++) {
411 sigs[i]= Signature.createTypeSignature(fParameterTypes[i].toCharArray(), false);
415 if (isConstructor()) {
416 name= getConstructorName();
420 return ((IType)parent).getMethod(name, sigs);
422 throw new IllegalArgumentException(Util.bind("element.illegalParent")); //$NON-NLS-1$
426 * @see DOMMember#getMemberDeclarationStartPosition()
428 protected int getMemberDeclarationStartPosition() {
429 if (fReturnTypeRange[0] >= 0) {
430 return fReturnTypeRange[0];
432 return fNameRange[0];
436 * @see IDOMNode#getName()
438 public String getName() {
439 if (isConstructor()) {
442 return super.getName();
446 * @see IDOMNode#getNodeType()
448 public int getNodeType() {
449 return IDOMNode.METHOD;
452 * @see IDOMMethod#getParameterNames()
454 public String[] getParameterNames() {
455 return fParameterNames;
458 * @see IDOMMethod#getParameterTypes()
460 public String[] getParameterTypes() {
461 return fParameterTypes;
464 * @see IDOMMethod#getReturnType()
466 public String getReturnType() {
467 if (isConstructor()) {
474 * Returns the source code to be used for this method's return type
476 protected char[] getReturnTypeContents() {
477 if (isConstructor()) {
480 if (isReturnTypeAltered()) {
481 return fReturnType.toCharArray();
483 return CharArrayOps.subarray(fDocument, fReturnTypeRange[0], fReturnTypeRange[1] + 1 - fReturnTypeRange[0]);
489 * Returns true if this method's return type has
490 * array qualifiers ('[]') following the parameter list.
492 protected boolean hasTrailingArrayQualifier() {
493 return fReturnTypeRange.length > 2;
496 * @see IDOMMethod#isConstructor()
498 public boolean isConstructor() {
499 return getMask(MASK_IS_CONSTRUCTOR);
502 * Returns true if this method's return type has been altered
503 * from the original document contents.
505 protected boolean isReturnTypeAltered() {
506 return getMask(MASK_RETURN_TYPE_ALTERED);
509 * @see IDOMNode#isSigantureEqual(IDOMNode).
511 * <p>Two methods have equal signatures if there names are the same
512 * and their parameter types are the same.
514 public boolean isSignatureEqual(IDOMNode node) {
515 boolean ok= node.getNodeType() == getNodeType();
517 IDOMMethod method= (IDOMMethod)node;
518 ok = (isConstructor() && method.isConstructor()) ||
519 (!isConstructor() && !method.isConstructor());
520 if (ok && !isConstructor()) {
521 ok= getName().equals(method.getName());
527 String[] types= method.getParameterTypes();
528 if (fParameterTypes == null || fParameterTypes.length == 0) {
529 // this method has no parameters
530 if (types == null || types.length == 0) {
531 // the other method has no parameters either
535 // this method has parameters
536 if (types == null || types.length == 0) {
537 // the other method has no parameters
540 if (fParameterTypes.length != types.length) {
541 // the methods have a different number of parameters
545 for (i= 0; i < types.length; i++) {
546 if (!fParameterTypes[i].equals(types[i])) {
559 protected DOMNode newDOMNode() {
560 return new DOMMethod();
563 * Offsets all the source indexes in this node by the given amount.
565 protected void offset(int offset) {
566 super.offset(offset);
567 offsetRange(fBodyRange, offset);
568 offsetRange(fExceptionRange, offset);
569 offsetRange(fParameterRange, offset);
570 offsetRange(fReturnTypeRange, offset);
573 * @see IDOMMethod#setBody
575 public void setBody(String body) {
579 setHasBody(body != null);
581 fBody= ";"+Util.LINE_SEPARATOR; //$NON-NLS-1$
585 * Sets the end of the body range
587 void setBodyRangeEnd(int end) {
591 * @see IDOMMethod#setConstructor(boolean)
593 public void setConstructor(boolean b) {
595 setMask(MASK_IS_CONSTRUCTOR, b);
599 * @see IDOMMethod#setExceptions(char[][])
601 public void setExceptions(String[] names) {
603 if (names == null || names.length == 0) {
607 CharArrayBuffer buffer = new CharArrayBuffer();
608 char[] comma = new char[] {',', ' '};
609 for (int i = 0, length = names.length; i < length; i++) {
611 buffer.append(comma);
612 buffer.append(names[i]);
614 fExceptionList= buffer.getContents();
619 * @see IDOMMethod#setName
621 public void setName(String name) {
623 throw new IllegalArgumentException(Util.bind("element.nullName")); //$NON-NLS-1$
629 * @see IDOMMethod#setParameters(char[][], char[][])
631 public void setParameters(String[] types, String[] names) throws IllegalArgumentException {
633 if (types== null || names == null) {
634 if (types == null && names == null) {
635 fParameterTypes= null;
636 fParameterNames= null;
637 fParameterList= new char[] {'(',')'};
639 throw new IllegalArgumentException(Util.bind("dom.mismatchArgNamesAndTypes")); //$NON-NLS-1$
641 } else if (names.length != types.length) {
642 throw new IllegalArgumentException(Util.bind("dom.mismatchArgNamesAndTypes")); //$NON-NLS-1$
643 } else if (names.length == 0) {
644 setParameters(null, null);
646 fParameterNames= names;
647 fParameterTypes= types;
648 CharArrayBuffer parametersBuffer = new CharArrayBuffer();
649 parametersBuffer.append("("); //$NON-NLS-1$
650 char[] comma = new char[] {',', ' '};
651 for (int i = 0; i < names.length; i++) {
653 parametersBuffer.append(comma);
660 parametersBuffer.append(')');
661 fParameterList= parametersBuffer.getContents();
666 * @see IDOMMethod#setReturnType(char[])
668 public void setReturnType(String name) throws IllegalArgumentException {
670 throw new IllegalArgumentException(Util.bind("dom.nullReturnType")); //$NON-NLS-1$
674 setReturnTypeAltered(true);
678 * Sets the state of this method declaration as having
679 * the return type altered from the original document.
681 protected void setReturnTypeAltered(boolean typeAltered) {
682 setMask(MASK_RETURN_TYPE_ALTERED, typeAltered);
686 protected void setSourceRangeEnd(int end) {
687 super.setSourceRangeEnd(end);
691 * @see DOMNode#shareContents(DOMNode)
693 protected void shareContents(DOMNode node) {
694 super.shareContents(node);
695 DOMMethod method= (DOMMethod)node;
697 fBodyRange= rangeCopy(method.fBodyRange);
698 fExceptionList= method.fExceptionList;
699 fExceptionRange= rangeCopy(method.fExceptionRange);
700 fExceptions= method.fExceptions;
701 fParameterList= method.fParameterList;
702 fParameterNames= method.fParameterNames;
703 fParameterRange= rangeCopy(method.fParameterRange);
704 fParameterTypes= method.fParameterTypes;
705 fReturnType= method.fReturnType;
706 fReturnTypeRange= rangeCopy(method.fReturnTypeRange);
709 * @see IDOMNode#toString()
711 public String toString() {
712 if (isConstructor()) {
713 return "CONSTRUCTOR"; //$NON-NLS-1$
715 return "METHOD: " + getName(); //$NON-NLS-1$