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