1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / jdom / DOMType.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.jdom;
12
13 import java.util.Enumeration;
14
15 import net.sourceforge.phpdt.core.ICompilationUnit;
16 import net.sourceforge.phpdt.core.IJavaElement;
17 import net.sourceforge.phpdt.core.IType;
18 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
19 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName;
20 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
21 import net.sourceforge.phpdt.core.jdom.IDOMMethod;
22 import net.sourceforge.phpdt.core.jdom.IDOMNode;
23 import net.sourceforge.phpdt.core.jdom.IDOMType;
24 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
25 import net.sourceforge.phpdt.internal.compiler.util.Util;
26 import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
27 import net.sourceforge.phpdt.internal.core.util.CharArrayOps;
28
29 /**
30  * DOMType provides an implementation of IDOMType.
31  * 
32  * @see IDOMType
33  * @see DOMNode
34  */
35
36 /* package */class DOMType extends DOMMember implements IDOMType {
37
38         /**
39          * The 'class' or 'interface' keyword if altered from the documents
40          * contents, otherwise <code>null</code>.
41          */
42         protected String fTypeKeyword;
43
44         /**
45          * The original inclusive source range of the 'class' or 'interface' keyword
46          * in the document.
47          */
48         protected int[] fTypeRange;
49
50         /**
51          * The superclass name for the class declaration if altered from the
52          * document's contents, otherwise <code>null</code>. Also
53          * <code>null</code> when this type represents an interface.
54          */
55         protected String fSuperclass;
56
57         /**
58          * The original inclusive source range of the superclass name in the
59          * document, or -1's of no superclass was specified in the document.
60          */
61         protected int[] fSuperclassRange;
62
63         /**
64          * The original inclusive souce range of the 'extends' keyword in the
65          * document, including surrounding whitespace, or -1's if the keyword was
66          * not present in the document.
67          */
68         protected int[] fExtendsRange;
69
70         /**
71          * The original inclusive souce range of the 'implements' keyword in the
72          * document, including surrounding whitespace, or -1's if the keyword was
73          * not present in the document.
74          */
75         protected int[] fImplementsRange;
76
77         /**
78          * The comma delimited list of interfaces this type implements or extends,
79          * if altered from the document's contents, otherwise <code>null</code>.
80          * Also <code>null</code> if this type does not implement or extend any
81          * interfaces.
82          */
83         protected char[] fInterfaces;
84
85         /**
86          * The original inclusive source range of the list of interfaces this type
87          * implements or extends, not including any surrouding whitespace. If the
88          * document did not specify interfaces, this array contains -1's.
89          */
90         protected int[] fInterfacesRange;
91
92         /**
93          * The original source range of the first character following the type name
94          * superclass name, or interface list, up to and including the first
95          * character before the first type member.
96          */
97         protected int[] fOpenBodyRange;
98
99         /**
100          * The original source range of the first new line or non whitespace
101          * character preceding the close brace of the type's body, up to the and
102          * including the first character before the next node (if there are no
103          * following nodes, the range ends at the position of the last character in
104          * the document).
105          */
106         protected int[] fCloseBodyRange;
107
108         /**
109          * A list of interfaces this type extends or implements. <code>null</code>
110          * when this type does not extend or implement any interfaces.
111          */
112         protected String[] fSuperInterfaces = new String[0];
113
114         /**
115          * This position is the position of the end of the last line separator
116          * before the closing brace starting position of the receiver.
117          */
118         // protected int fInsertionPosition;
119         /**
120          * Constructs an empty type node.
121          */
122         DOMType() {
123
124         }
125
126         /**
127          * Creates a new detailed TYPE document fragment on the given range of the
128          * document.
129          * 
130          * @param document -
131          *            the document containing this node's original contents
132          * @param sourceRange -
133          *            a two element array of integers describing the entire
134          *            inclusive source range of this node within its document.
135          *            Contents start on and include the character at the first
136          *            position. Contents end on and include the character at the
137          *            last position. An array of -1's indicates this node's contents
138          *            do not exist in the document.
139          * @param name -
140          *            the identifier portion of the name of this node, or
141          *            <code>null</code> if this node does not have a name
142          * @param nameRange -
143          *            a two element array of integers describing the entire
144          *            inclusive source range of this node's name within its
145          *            document, including any array qualifiers that might
146          *            immediately follow the name or -1's if this node does not have
147          *            a name.
148          * @param commentRange -
149          *            a two element array describing the comments that precede the
150          *            member declaration. The first matches the start of this node's
151          *            sourceRange, and the second is the new-line or first
152          *            non-whitespace character following the last comment. If no
153          *            comments are present, this array contains two -1's.
154          * @param flags -
155          *            an integer representing the modifiers for this member. The
156          *            integer can be analyzed with net.sourceforge.phpdt.core.Flags
157          * @param modifierRange -
158          *            a two element array describing the location of modifiers for
159          *            this member within its source range. The first integer is the
160          *            first character of the first modifier for this member, and the
161          *            second integer is the last whitespace character preceeding the
162          *            next part of this member declaration. If there are no
163          *            modifiers present in this node's source code (that is, package
164          *            default visibility), this array contains two -1's.
165          * @param typeRange -
166          *            a two element array describing the location of the 'class' or
167          *            'interface' keyword in the type declaration - first and last
168          *            character positions.
169          * @param superclassRange -
170          *            a two element array describing the location of the superclass
171          *            name in the type declaration - first and last character
172          *            positions or two -1's if a superclass is not present in the
173          *            document.
174          * @param extendsRange -
175          *            a two element array describing the location of the 'extends'
176          *            keyword in the type declaration, including any surrounding
177          *            whitespace, or -1's if the 'extends' keyword is not present in
178          *            the document.
179          * @param implementsList -
180          *            an array of names of the interfaces this type implements or
181          *            extends, or <code>null</code> if this type does not
182          *            implement or extend any interfaces.
183          * @param implementsRange -
184          *            a two element array describing the location of the comment
185          *            delimited list of interfaces this type implements or extends,
186          *            not including any surrounding whitespace, or -1's if no
187          *            interface list is present in the document.
188          * @param implementsKeywordRange -
189          *            a two element array describing the location of the
190          *            'implements' keyword, including any surrounding whitespace, or
191          *            -1's if no 'implements' keyword is present in the document.
192          * @param openBodyRange -
193          *            a two element array describing the location of the open brace
194          *            of the type's body and whitespace following the type
195          *            declaration and preceeding the first member in the type.
196          * @param closeBodyRange -
197          *            a two element array describing the source range of the first
198          *            new line or non whitespace character preceeding the close
199          *            brace of the type's body, up to the close brace
200          * @param isClass -
201          *            true is the type is a class, false if it is an interface
202          */
203         DOMType(char[] document, int[] sourceRange, String name, int[] nameRange,
204                         int[] commentRange, int flags, int[] modifierRange,
205                         int[] typeRange, int[] superclassRange, int[] extendsRange,
206                         String[] implementsList, int[] implementsRange,
207                         int[] implementsKeywordRange, int[] openBodyRange,
208                         int[] closeBodyRange, boolean isClass) {
209                 super(document, sourceRange, name, nameRange, commentRange, flags,
210                                 modifierRange);
211
212                 fTypeRange = typeRange;
213                 setMask(MASK_TYPE_IS_CLASS, isClass);
214
215                 fExtendsRange = extendsRange;
216                 fImplementsRange = implementsKeywordRange;
217                 fSuperclassRange = superclassRange;
218                 fInterfacesRange = implementsRange;
219                 fCloseBodyRange = closeBodyRange;
220                 setMask(MASK_TYPE_HAS_SUPERCLASS, superclassRange[0] > 0);
221                 setMask(MASK_TYPE_HAS_INTERFACES, implementsList != null);
222                 fSuperInterfaces = implementsList;
223                 fOpenBodyRange = openBodyRange;
224                 fCloseBodyRange = closeBodyRange;
225                 setMask(MASK_DETAILED_SOURCE_INDEXES, true);
226
227         }
228
229         /**
230          * Creates a new simple TYPE document fragment on the given range of the
231          * document.
232          * 
233          * @param document -
234          *            the document containing this node's original contents
235          * @param sourceRange -
236          *            a two element array of integers describing the entire
237          *            inclusive source range of this node within its document.
238          *            Contents start on and include the character at the first
239          *            position. Contents end on and include the character at the
240          *            last position. An array of -1's indicates this node's contents
241          *            do not exist in the document.
242          * @param name -
243          *            the identifier portion of the name of this node, or
244          *            <code>null</code> if this node does not have a name
245          * @param nameRange -
246          *            a two element array of integers describing the entire
247          *            inclusive source range of this node's name within its
248          *            document, including any array qualifiers that might
249          *            immediately follow the name or -1's if this node does not have
250          *            a name.
251          * @param flags -
252          *            an integer representing the modifiers for this member. The
253          *            integer can be analyzed with net.sourceforge.phpdt.core.Flags
254          * @param implementsList -
255          *            an array of names of the interfaces this type implements or
256          *            extends, or <code>null</code> if this type does not
257          *            implement or extend any interfaces.
258          * @param isClass -
259          *            true is the type is a class, false if it is an interface
260          */
261         DOMType(char[] document, int[] sourceRange, String name, int[] nameRange,
262                         int flags, String[] implementsList, boolean isClass) {
263                 this(document, sourceRange, name, nameRange, new int[] { -1, -1 },
264                                 flags, new int[] { -1, -1 }, new int[] { -1, -1 }, new int[] {
265                                                 -1, -1 }, new int[] { -1, -1 }, implementsList,
266                                 new int[] { -1, -1 }, new int[] { -1, -1 },
267                                 new int[] { -1, -1 }, new int[] { sourceRange[1],
268                                                 sourceRange[1] }, isClass);
269                 setMask(MASK_DETAILED_SOURCE_INDEXES, false);
270         }
271
272         /**
273          * @see IDOMType#addSuperInterface(String)
274          */
275         public void addSuperInterface(String name) throws IllegalArgumentException {
276                 if (name == null) {
277                         throw new IllegalArgumentException(Util
278                                         .bind("dom.addNullInterface")); //$NON-NLS-1$
279                 }
280                 if (fSuperInterfaces == null) {
281                         fSuperInterfaces = new String[1];
282                         fSuperInterfaces[0] = name;
283                 } else {
284                         fSuperInterfaces = appendString(fSuperInterfaces, name);
285                 }
286                 setSuperInterfaces(fSuperInterfaces);
287         }
288
289         /**
290          * @see DOMMember#appendMemberBodyContents(CharArrayBuffer)
291          */
292         protected void appendMemberBodyContents(CharArrayBuffer buffer) {
293                 buffer.append(fDocument, fOpenBodyRange[0], fOpenBodyRange[1] + 1
294                                 - fOpenBodyRange[0]);
295                 appendContentsOfChildren(buffer);
296                 buffer.append(fDocument, fCloseBodyRange[0], fCloseBodyRange[1] + 1
297                                 - fCloseBodyRange[0]);
298                 buffer.append(fDocument, fCloseBodyRange[1] + 1, fSourceRange[1]
299                                 - fCloseBodyRange[1]);
300         }
301
302         /**
303          * @see DOMMember#appendMemberDeclarationContents(CharArrayBuffer )
304          */
305         protected void appendMemberDeclarationContents(CharArrayBuffer buffer) {
306
307                 if (fTypeKeyword != null) {
308                         buffer.append(fTypeKeyword);
309                         buffer.append(fDocument, fTypeRange[1], fNameRange[0]
310                                         - fTypeRange[1]);
311                 } else {
312                         buffer.append(fDocument, fTypeRange[0], fTypeRange[1] + 1
313                                         - fTypeRange[0]);
314                 }
315
316                 buffer.append(getName());
317
318                 if (isClass()) {
319                         boolean hasSuperclass = false, hasInterfaces = false;
320                         if (getMask(MASK_TYPE_HAS_SUPERCLASS)) {
321                                 hasSuperclass = true;
322                                 if (fExtendsRange[0] < 0) {
323                                         buffer.append(" extends "); //$NON-NLS-1$
324                                 } else {
325                                         buffer.append(fDocument, fExtendsRange[0], fExtendsRange[1]
326                                                         + 1 - fExtendsRange[0]);
327                                 }
328                                 if (fSuperclass != null) {
329                                         buffer.append(fSuperclass);
330                                 } else {
331                                         buffer.append(fDocument, fSuperclassRange[0],
332                                                         fSuperclassRange[1] + 1 - fSuperclassRange[0]);
333                                 }
334                         }
335                         if (getMask(MASK_TYPE_HAS_INTERFACES)) {
336                                 hasInterfaces = true;
337                                 if (fImplementsRange[0] < 0) {
338                                         buffer.append(" implements "); //$NON-NLS-1$
339                                 } else {
340                                         buffer.append(fDocument, fImplementsRange[0],
341                                                         fImplementsRange[1] + 1 - fImplementsRange[0]);
342                                 }
343                                 if (fInterfaces != null) {
344                                         buffer.append(fInterfaces);
345                                 } else {
346                                         buffer.append(fDocument, fInterfacesRange[0],
347                                                         fInterfacesRange[1] + 1 - fInterfacesRange[0]);
348                                 }
349                         }
350                         if (hasInterfaces) {
351                                 if (fImplementsRange[0] < 0) {
352                                         buffer.append(' ');
353                                 } else {
354                                         buffer.append(fDocument, fInterfacesRange[1] + 1,
355                                                         fOpenBodyRange[0] - fInterfacesRange[1] - 1);
356                                 }
357                         } else {
358                                 if (hasSuperclass) {
359                                         if (fSuperclassRange[0] < 0) {
360                                                 buffer.append(' ');
361                                         } else {
362                                                 buffer.append(fDocument, fSuperclassRange[1] + 1,
363                                                                 fOpenBodyRange[0] - fSuperclassRange[1] - 1);
364                                         }
365                                 } else {
366                                         buffer.append(fDocument, fNameRange[1] + 1,
367                                                         fOpenBodyRange[0] - fNameRange[1] - 1);
368                                 }
369                         }
370                 } else {
371                         if (getMask(MASK_TYPE_HAS_INTERFACES)) {
372                                 if (fExtendsRange[0] < 0) {
373                                         buffer.append(" extends "); //$NON-NLS-1$
374                                 } else {
375                                         buffer.append(fDocument, fExtendsRange[0], fExtendsRange[1]
376                                                         + 1 - fExtendsRange[0]);
377                                 }
378                                 if (fInterfaces != null) {
379                                         buffer.append(fInterfaces);
380                                         buffer.append(' ');
381                                 } else {
382                                         buffer.append(fDocument, fInterfacesRange[0],
383                                                         fInterfacesRange[1] + 1 - fInterfacesRange[0]);
384                                 }
385                         } else {
386                                 buffer.append(fDocument, fNameRange[1] + 1, fOpenBodyRange[0]
387                                                 - fNameRange[1] - 1);
388                         }
389                 }
390
391         }
392
393         /**
394          * @see DOMNode#appendSimpleContents(CharArrayBuffer)
395          */
396         protected void appendSimpleContents(CharArrayBuffer buffer) {
397                 // append eveything before my name
398                 buffer.append(fDocument, fSourceRange[0], fNameRange[0]
399                                 - fSourceRange[0]);
400                 // append my name
401                 buffer.append(fName);
402
403                 // append everything after my name and before my first child
404                 buffer.append(fDocument, fNameRange[1] + 1, fOpenBodyRange[1]
405                                 - fNameRange[1]);
406                 // append my children
407                 appendContentsOfChildren(buffer);
408                 // append from my last child to my end
409                 buffer.append(fDocument, fCloseBodyRange[0], fSourceRange[1]
410                                 - fCloseBodyRange[0] + 1);
411
412         }
413
414         /**
415          * @see IDOMNode#canHaveChildren()
416          */
417         public boolean canHaveChildren() {
418                 return true;
419         }
420
421         /**
422          * Returns the position of the closing brace for the body of this type. This
423          * value this method returns is only valid before the type has been
424          * normalized and is present only for normalization.
425          */
426         int getCloseBodyPosition() {
427                 return fCloseBodyRange[0];
428         }
429
430         /**
431          * @see DOMNode#getDetailedNode()
432          */
433         // protected DOMNode getDetailedNode() {
434         // return (DOMNode)getFactory().createType(getContents());
435         // }
436         /**
437          * @see DOMNode#getInsertionPosition()
438          */
439         public int getInsertionPosition() {
440                 // this should return the position of the end of the last line separator
441                 // before the closing brace of the type
442                 // See PR 1GELSDQ: ITPJUI:WINNT - JDOM: IType.createMethod does not
443                 // insert nicely for inner types
444                 return fInsertionPosition;
445         }
446
447         /**
448          * @see IDOMNode#getJavaElement
449          */
450         public IJavaElement getJavaElement(IJavaElement parent)
451                         throws IllegalArgumentException {
452                 if (parent.getElementType() == IJavaElement.TYPE) {
453                         return ((IType) parent).getType(getName());
454                 } else if (parent.getElementType() == IJavaElement.COMPILATION_UNIT) {
455                         return ((ICompilationUnit) parent).getType(getName());
456                 } else {
457                         throw new IllegalArgumentException(Util
458                                         .bind("element.illegalParent")); //$NON-NLS-1$
459                 }
460         }
461
462         /**
463          * @see DOMMember#getMemberDeclarationStartPosition()
464          */
465         protected int getMemberDeclarationStartPosition() {
466                 return fTypeRange[0];
467         }
468
469         /**
470          * @see IDOMNode#getNodeType()
471          */
472         public int getNodeType() {
473                 return IDOMNode.TYPE;
474         }
475
476         /**
477          * Answers the open body range end position.
478          */
479         int getOpenBodyEnd() {
480                 return fOpenBodyRange[1];
481         }
482
483         /**
484          * @see IDOMType#getSuperclass()
485          */
486         public String getSuperclass() {
487                 becomeDetailed();
488                 if (getMask(MASK_TYPE_HAS_SUPERCLASS)) {
489                         if (fSuperclass != null) {
490                                 return fSuperclass;
491                         } else {
492                                 return CharArrayOps.substring(fDocument, fSuperclassRange[0],
493                                                 fSuperclassRange[1] + 1 - fSuperclassRange[0]);
494                         }
495                 } else {
496                         return null;
497                 }
498         }
499
500         /**
501          * @see IDOMType#getSuperInterfaces()
502          */
503         public String[] getSuperInterfaces() {
504                 return fSuperInterfaces;
505         }
506
507         /**
508          * @see IDOMNode
509          */
510         public boolean isAllowableChild(IDOMNode node) {
511                 if (node != null) {
512                         int type = node.getNodeType();
513                         return type == IDOMNode.TYPE || type == IDOMNode.FIELD
514                                         || type == IDOMNode.METHOD || type == IDOMNode.INITIALIZER;
515                 } else {
516                         return false;
517                 }
518
519         }
520
521         /**
522          * @see IDOMType#isClass()
523          */
524         public boolean isClass() {
525                 return getMask(MASK_TYPE_IS_CLASS);
526         }
527
528         /**
529          * @see DOMNode
530          */
531         protected DOMNode newDOMNode() {
532                 return new DOMType();
533         }
534
535         /**
536          * Normalizes this <code>DOMNode</code>'s source positions to include
537          * whitespace preceeding the node on the line on which the node starts, and
538          * all whitespace after the node up to the next node's start
539          */
540         void normalize(ILineStartFinder finder) {
541                 // perform final changes to the open and close body ranges
542                 int openBodyEnd, openBodyStart, closeBodyStart, closeBodyEnd;
543                 DOMNode first = (DOMNode) getFirstChild();
544                 DOMNode lastNode = null;
545                 // look for the open body
546                 Scanner scanner = new Scanner();
547                 scanner.setSource(fDocument);
548                 scanner.resetTo(fNameRange[1] + 1, fDocument.length);
549
550                 try {
551                         TokenName currentToken = scanner.getNextToken();
552                         while (currentToken != ITerminalSymbols.TokenName.LBRACE
553                                         && currentToken != ITerminalSymbols.TokenName.EOF) {
554                                 currentToken = scanner.getNextToken();
555                         }
556                         if (currentToken == ITerminalSymbols.TokenName.LBRACE) {
557                                 openBodyEnd = scanner.currentPosition - 1;
558                                 openBodyStart = scanner.startPosition;
559                         } else {
560                                 openBodyEnd = fDocument.length;
561                                 openBodyStart = fDocument.length;
562                         }
563                 } catch (InvalidInputException e) {
564                         openBodyEnd = fDocument.length;
565                         openBodyStart = fDocument.length;
566                 }
567                 if (first != null) {
568                         int lineStart = finder.getLineStart(first.getStartPosition());
569                         if (lineStart > openBodyEnd) {
570                                 openBodyEnd = lineStart - 1;
571                         } else {
572                                 openBodyEnd = first.getStartPosition() - 1;
573                         }
574                         lastNode = (DOMNode) first.getNextNode();
575                         if (lastNode == null) {
576                                 lastNode = first;
577                         } else {
578                                 while (lastNode.getNextNode() != null) {
579                                         lastNode = (DOMNode) lastNode.getNextNode();
580                                 }
581                         }
582                         scanner.setSource(fDocument);
583                         scanner.resetTo(lastNode.getEndPosition() + 1, fDocument.length);
584                         try {
585                                 TokenName currentToken = scanner.getNextToken();
586                                 while (currentToken != ITerminalSymbols.TokenName.RBRACE
587                                                 && currentToken != ITerminalSymbols.TokenName.EOF) {
588                                         currentToken = scanner.getNextToken();
589                                 }
590                                 if (currentToken == ITerminalSymbols.TokenName.RBRACE) {
591                                         closeBodyStart = scanner.startPosition;
592                                         closeBodyEnd = scanner.currentPosition - 1;
593                                 } else {
594                                         closeBodyStart = fDocument.length;
595                                         closeBodyEnd = fDocument.length;
596                                 }
597                         } catch (InvalidInputException e) {
598                                 closeBodyStart = fDocument.length;
599                                 closeBodyEnd = fDocument.length;
600                         }
601                 } else {
602                         scanner.resetTo(openBodyEnd, fDocument.length);
603                         try {
604                                 TokenName currentToken = scanner.getNextToken();
605                                 while (currentToken != ITerminalSymbols.TokenName.RBRACE
606                                                 && currentToken != ITerminalSymbols.TokenName.EOF) {
607                                         currentToken = scanner.getNextToken();
608                                 }
609                                 if (currentToken == ITerminalSymbols.TokenName.RBRACE) {
610                                         closeBodyStart = scanner.startPosition;
611                                         closeBodyEnd = scanner.currentPosition - 1;
612                                 } else {
613                                         closeBodyStart = fDocument.length;
614                                         closeBodyEnd = fDocument.length;
615                                 }
616                         } catch (InvalidInputException e) {
617                                 closeBodyStart = fDocument.length;
618                                 closeBodyEnd = fDocument.length;
619                         }
620                         openBodyEnd = closeBodyEnd - 1;
621                 }
622                 setOpenBodyRangeEnd(openBodyEnd);
623                 setOpenBodyRangeStart(openBodyStart);
624                 setCloseBodyRangeStart(closeBodyStart);
625                 setCloseBodyRangeEnd(closeBodyEnd);
626                 fInsertionPosition = finder.getLineStart(closeBodyStart);
627                 if (lastNode != null && fInsertionPosition < lastNode.getEndPosition()) {
628                         fInsertionPosition = getCloseBodyPosition();
629                 }
630                 if (fInsertionPosition <= openBodyEnd) {
631                         fInsertionPosition = getCloseBodyPosition();
632                 }
633                 super.normalize(finder);
634         }
635
636         /**
637          * Normalizes this <code>DOMNode</code>'s end position.
638          */
639         void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
640                 if (next == null) {
641                         // this node's end position includes all of the characters up
642                         // to the end of the enclosing node
643                         DOMNode parent = (DOMNode) getParent();
644                         if (parent == null || parent instanceof DOMCompilationUnit) {
645                                 setSourceRangeEnd(fDocument.length - 1);
646                         } else {
647                                 // parent is a type
648                                 setSourceRangeEnd(((DOMType) parent).getCloseBodyPosition() - 1);
649                         }
650                 } else {
651                         // this node's end position is just before the start of the next
652                         // node
653                         next.normalizeStartPosition(getEndPosition(), finder);
654                         setSourceRangeEnd(next.getStartPosition() - 1);
655                 }
656         }
657
658         /**
659          * Offsets all the source indexes in this node by the given amount.
660          */
661         protected void offset(int offset) {
662                 super.offset(offset);
663                 offsetRange(fCloseBodyRange, offset);
664                 offsetRange(fExtendsRange, offset);
665                 offsetRange(fImplementsRange, offset);
666                 offsetRange(fInterfacesRange, offset);
667                 offsetRange(fOpenBodyRange, offset);
668                 offsetRange(fSuperclassRange, offset);
669                 offsetRange(fTypeRange, offset);
670         }
671
672         /**
673          * @see IDOMType#setClass(boolean)
674          */
675         public void setClass(boolean b) {
676                 becomeDetailed();
677                 fragment();
678                 setMask(MASK_TYPE_IS_CLASS, b);
679                 if (b) {
680                         fTypeKeyword = "class"; //$NON-NLS-1$
681                 } else {
682                         fTypeKeyword = "interface"; //$NON-NLS-1$
683                         setSuperclass(null);
684                 }
685         }
686
687         /**
688          * Sets the end of the close body range
689          */
690         void setCloseBodyRangeEnd(int end) {
691                 fCloseBodyRange[1] = end;
692         }
693
694         /**
695          * Sets the start of the close body range
696          */
697         void setCloseBodyRangeStart(int start) {
698                 fCloseBodyRange[0] = start;
699         }
700
701         /**
702          * Sets the name of this node.
703          * 
704          * <p>
705          * When the name of a type is set, all of its constructors must be marked as
706          * fragmented, since the names of the constructors must reflect the name of
707          * this type.
708          * 
709          * @see IDOMNode#setName(char[])
710          */
711         public void setName(String name) throws IllegalArgumentException {
712                 if (name == null) {
713                         throw new IllegalArgumentException(Util.bind("element.nullName")); //$NON-NLS-1$
714                 }
715                 super.setName(name);
716                 Enumeration children = getChildren();
717                 while (children.hasMoreElements()) {
718                         IDOMNode child = (IDOMNode) children.nextElement();
719                         if (child.getNodeType() == IDOMNode.METHOD
720                                         && ((IDOMMethod) child).isConstructor()) {
721                                 ((DOMNode) child).fragment();
722                         }
723                 }
724         }
725
726         /**
727          * Sets the end of the open body range
728          */
729         void setOpenBodyRangeEnd(int end) {
730                 fOpenBodyRange[1] = end;
731         }
732
733         /**
734          * Sets the start of the open body range
735          */
736         void setOpenBodyRangeStart(int start) {
737                 fOpenBodyRange[0] = start;
738         }
739
740         /**
741          * @see IDOMType#setSuperclass(char[])
742          */
743         public void setSuperclass(String superclassName) {
744                 becomeDetailed();
745                 fragment();
746                 fSuperclass = superclassName;
747                 setMask(MASK_TYPE_HAS_SUPERCLASS, superclassName != null);
748         }
749
750         /**
751          * @see IDOMType#setSuperInterfaces(String[])
752          */
753         public void setSuperInterfaces(String[] names) {
754                 becomeDetailed();
755                 if (names == null) {
756                         throw new IllegalArgumentException(Util.bind("dom.nullInterfaces")); //$NON-NLS-1$
757                 }
758                 fragment();
759                 fSuperInterfaces = names;
760                 if (names == null || names.length == 0) {
761                         fInterfaces = null;
762                         fSuperInterfaces = null;
763                         setMask(MASK_TYPE_HAS_INTERFACES, false);
764                 } else {
765                         setMask(MASK_TYPE_HAS_INTERFACES, true);
766                         CharArrayBuffer buffer = new CharArrayBuffer();
767                         for (int i = 0; i < names.length; i++) {
768                                 if (i > 0) {
769                                         buffer.append(", "); //$NON-NLS-1$
770                                 }
771                                 buffer.append(names[i]);
772                         }
773                         fInterfaces = buffer.getContents();
774                 }
775         }
776
777         /**
778          * Sets the type keyword
779          */
780 //      void setTypeKeyword(String keyword) {
781 //              fTypeKeyword = keyword;
782 //      }
783
784         /**
785          * @see DOMNode#shareContents(DOMNode)
786          */
787         protected void shareContents(DOMNode node) {
788                 super.shareContents(node);
789                 DOMType type = (DOMType) node;
790                 fCloseBodyRange = rangeCopy(type.fCloseBodyRange);
791                 fExtendsRange = type.fExtendsRange;
792                 fImplementsRange = rangeCopy(type.fImplementsRange);
793                 fInterfaces = type.fInterfaces;
794                 fInterfacesRange = rangeCopy(type.fInterfacesRange);
795                 fOpenBodyRange = rangeCopy(type.fOpenBodyRange);
796                 fSuperclass = type.fSuperclass;
797                 fSuperclassRange = rangeCopy(type.fSuperclassRange);
798                 fSuperInterfaces = type.fSuperInterfaces;
799                 fTypeKeyword = type.fTypeKeyword;
800                 fTypeRange = rangeCopy(type.fTypeRange);
801         }
802
803         /**
804          * @see IDOMNode#toString()
805          */
806         public String toString() {
807                 return "TYPE: " + getName(); //$NON-NLS-1$
808         }
809 }