001: /*******************************************************************************
002: * Copyright (c) 2004, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.core.dom;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.core.compiler.InvalidInputException;
014: import org.eclipse.jdt.internal.compiler.parser.Scanner;
015: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
016: import org.eclipse.jdt.internal.compiler.util.Util;
017:
018: /**
019: * Internal class for associating comments with AST nodes.
020: *
021: * @since 3.0
022: */
023: class DefaultCommentMapper {
024: Comment[] comments;
025: Scanner scanner;
026:
027: // extended nodes storage
028: int leadingPtr;
029: ASTNode[] leadingNodes;
030: long[] leadingIndexes;
031: int trailingPtr, lastTrailingPtr;
032: ASTNode[] trailingNodes;
033: long[] trailingIndexes;
034: static final int STORAGE_INCREMENT = 16;
035:
036: /**
037: * @param table the given table of comments
038: */
039: DefaultCommentMapper(Comment[] table) {
040: this .comments = table;
041: }
042:
043: boolean hasSameTable(Comment[] table) {
044: return this .comments == table;
045: }
046:
047: /**
048: * Get comment of the list which includes a given position
049: *
050: * @param position The position belonging to the looked up comment
051: * @return comment which includes the given position or null if none was found
052: */
053: Comment getComment(int position) {
054:
055: if (this .comments == null) {
056: return null;
057: }
058: int size = this .comments.length;
059: if (size == 0) {
060: return null;
061: }
062: int index = getCommentIndex(0, position, 0);
063: if (index < 0) {
064: return null;
065: }
066: return this .comments[index];
067: }
068:
069: /*
070: * Get the index of comment which contains given position.
071: * If there's no matching comment, then return depends on exact parameter:
072: * = 0: return -1
073: * < 0: return index of the comment before the given position
074: * > 0: return index of the comment after the given position
075: */
076: private int getCommentIndex(int start, int position, int exact) {
077: if (position == 0) {
078: if (this .comments.length > 0
079: && this .comments[0].getStartPosition() == 0) {
080: return 0;
081: }
082: return -1;
083: }
084: int bottom = start, top = this .comments.length - 1;
085: int i = 0, index = -1;
086: Comment comment = null;
087: while (bottom <= top) {
088: i = bottom + (top - bottom) / 2;
089: comment = this .comments[i];
090: int commentStart = comment.getStartPosition();
091: if (position < commentStart) {
092: top = i - 1;
093: } else if (position >= (commentStart + comment.getLength())) {
094: bottom = i + 1;
095: } else {
096: index = i;
097: break;
098: }
099: }
100: if (index < 0 && exact != 0) {
101: comment = this .comments[i];
102: if (position < comment.getStartPosition()) {
103: return exact < 0 ? i - 1 : i;
104: } else {
105: return exact < 0 ? i : i + 1;
106: }
107: }
108: return index;
109: }
110:
111: /**
112: * Returns the extended start position of the given node. Unlike
113: * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
114: * the extended source range may include comments and whitespace
115: * immediately before or after the normal source range for the node.
116: *
117: * @param node the node
118: * @return the 0-based character index, or <code>-1</code>
119: * if no source position information is recorded for this node
120: * @see #getExtendedLength(ASTNode)
121: * @since 3.0
122: */
123: public int getExtendedStartPosition(ASTNode node) {
124: if (this .leadingPtr >= 0) {
125: long range = -1;
126: for (int i = 0; range < 0 && i <= this .leadingPtr; i++) {
127: if (this .leadingNodes[i] == node)
128: range = this .leadingIndexes[i];
129: }
130: if (range >= 0) {
131: return this .comments[(int) (range >> 32)]
132: .getStartPosition();
133: }
134: }
135: return node.getStartPosition();
136: }
137:
138: /*
139: * Search the line number corresponding to a specific position
140: * between the given line range (inclusive)
141: * @param position int
142: * @parem lineRange size-2 int[]
143: * @return int
144: */
145: public final int getLineNumber(int position, int[] lineRange) {
146: int[] lineEnds = this .scanner.lineEnds;
147: int length = lineEnds.length;
148: return Util.getLineNumber(position, lineEnds,
149: (lineRange[0] > length ? length : lineRange[0]) - 1,
150: (lineRange[1] > length ? length : lineRange[1]) - 1);
151: }
152:
153: /*
154: * Returns the extended end position of the given node.
155: */
156: public int getExtendedEnd(ASTNode node) {
157: int end = node.getStartPosition() + node.getLength();
158: if (this .trailingPtr >= 0) {
159: long range = -1;
160: for (int i = 0; range < 0 && i <= this .trailingPtr; i++) {
161: if (this .trailingNodes[i] == node)
162: range = this .trailingIndexes[i];
163: }
164: if (range >= 0) {
165: Comment lastComment = this .comments[(int) range];
166: end = lastComment.getStartPosition()
167: + lastComment.getLength();
168: }
169: }
170: return end - 1;
171: }
172:
173: /**
174: * Returns the extended source length of the given node. Unlike
175: * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
176: * the extended source range may include comments and whitespace
177: * immediately before or after the normal source range for the node.
178: *
179: * @param node the node
180: * @return a (possibly 0) length, or <code>0</code>
181: * if no source position information is recorded for this node
182: * @see #getExtendedStartPosition(ASTNode)
183: * @see #getExtendedEnd(ASTNode)
184: * @since 3.0
185: */
186: public int getExtendedLength(ASTNode node) {
187: return getExtendedEnd(node) - getExtendedStartPosition(node)
188: + 1;
189: }
190:
191: /**
192: * Return index of first leading comment of a given node.
193: *
194: * @param node
195: * @return index of first leading comment or -1 if node has no leading comment
196: */
197: int firstLeadingCommentIndex(ASTNode node) {
198: if (this .leadingPtr >= 0) {
199: for (int i = 0; i <= this .leadingPtr; i++) {
200: if (this .leadingNodes[i] == node) {
201: return (int) (this .leadingIndexes[i] >> 32);
202: }
203: }
204: }
205: return -1;
206: }
207:
208: /**
209: * Return index of last trailing comment of a given node.
210: *
211: * @param node
212: * @return index of last trailing comment or -1 if node has no trailing comment
213: */
214: int lastTrailingCommentIndex(ASTNode node) {
215: if (this .trailingPtr >= 0) {
216: for (int i = 0; i <= this .trailingPtr; i++) {
217: if (this .trailingNodes[i] == node) {
218: return (int) this .trailingIndexes[i];
219: }
220: }
221: }
222: return -1;
223: }
224:
225: /*
226: * Initialize leading and trailing comments tables in whole nodes hierarchy of a compilation
227: * unit.
228: * Scanner is necessary to scan between nodes and comments and verify if there's
229: * nothing else than white spaces.
230: */
231: void initialize(CompilationUnit unit, Scanner sc) {
232:
233: // Init array pointers
234: this .leadingPtr = -1;
235: this .trailingPtr = -1;
236:
237: // Init comments
238: this .comments = unit.optionalCommentTable;
239: if (this .comments == null) {
240: return;
241: }
242: int size = this .comments.length;
243: if (size == 0) {
244: return;
245: }
246:
247: // Init scanner and start ranges computing
248: this .scanner = sc;
249: this .scanner.tokenizeWhiteSpace = true;
250:
251: // Start unit visit
252: DefaultASTVisitor commentVisitor = new CommentMapperVisitor();
253: unit.accept(commentVisitor);
254:
255: // Reduce leading arrays if necessary
256: int leadingCount = this .leadingPtr + 1;
257: if (leadingCount > 0
258: && leadingCount < this .leadingIndexes.length) {
259: System.arraycopy(this .leadingNodes, 0,
260: this .leadingNodes = new ASTNode[leadingCount], 0,
261: leadingCount);
262: System.arraycopy(this .leadingIndexes, 0,
263: this .leadingIndexes = new long[leadingCount], 0,
264: leadingCount);
265: }
266:
267: // Reduce trailing arrays if necessary
268: if (this .trailingPtr >= 0) {
269: // remove last remaining unresolved nodes
270: while (this .trailingIndexes[this .trailingPtr] == -1) {
271: this .trailingPtr--;
272: if (this .trailingPtr < 0) {
273: this .trailingIndexes = null;
274: this .trailingNodes = null;
275: break;
276: }
277: }
278:
279: // reduce array size
280: int trailingCount = this .trailingPtr + 1;
281: if (trailingCount > 0
282: && trailingCount < this .trailingIndexes.length) {
283: System
284: .arraycopy(
285: this .trailingNodes,
286: 0,
287: this .trailingNodes = new ASTNode[trailingCount],
288: 0, trailingCount);
289: System.arraycopy(this .trailingIndexes, 0,
290: this .trailingIndexes = new long[trailingCount],
291: 0, trailingCount);
292: }
293: }
294:
295: // Release scanner as it's only used during unit visit
296: this .scanner = null;
297: }
298:
299: /**
300: * Search and store node leading comments. Comments are searched in position range
301: * from previous extended position to node start position. If one or several comment are found,
302: * returns first comment start position, otherwise returns node start position.
303: * <p>
304: * Starts to search for first comment before node start position and return if none was found...
305: *</p><p>
306: * When first comment is found before node, goes up in comment list until one of
307: * following conditions becomes true:
308: * <ol>
309: * <li>comment end is before previous end</li>
310: * <li>comment start and previous end is on the same line but not on same line of node start</li>
311: * <li>there's other than white characters between current node and comment</li>
312: * <li>there's more than 1 line between current node and comment</li>
313: * </ol>
314: * If some comment have been found, then no token should be on
315: * on the same line before, so remove all comments which do not verify this assumption.
316: * </p><p>
317: * If finally there's leading still comments, then stores indexes of the first and last one
318: * in leading comments table.
319: */
320: int storeLeadingComments(ASTNode node, int previousEnd,
321: int[] parentLineRange) {
322: // Init extended position
323: int nodeStart = node.getStartPosition();
324: int extended = nodeStart;
325:
326: // Get line of node start position
327: int previousEndLine = getLineNumber(previousEnd,
328: parentLineRange);
329: int nodeStartLine = getLineNumber(nodeStart, parentLineRange);
330:
331: // Find first comment index
332: int idx = getCommentIndex(0, nodeStart, -1);
333: if (idx == -1) {
334: return nodeStart;
335: }
336:
337: // Look after potential comments
338: int startIdx = -1;
339: int endIdx = idx;
340: int previousStart = nodeStart;
341: while (idx >= 0 && previousStart >= previousEnd) {
342: // Verify for each comment that there's only white spaces between end and start of {following comment|node}
343: Comment comment = this .comments[idx];
344: int commentStart = comment.getStartPosition();
345: int end = commentStart + comment.getLength() - 1;
346: int commentLine = getLineNumber(commentStart,
347: parentLineRange);
348: if (end <= previousEnd
349: || (commentLine == previousEndLine && commentLine != nodeStartLine)) {
350: // stop search on condition 1) and 2)
351: break;
352: } else if ((end + 1) < previousStart) { // may be equals => then no scan is necessary
353: this .scanner.resetTo(end + 1, previousStart);
354: try {
355: int token = this .scanner.getNextToken();
356: if (token != TerminalTokens.TokenNameWHITESPACE
357: || this .scanner.currentPosition != previousStart) {
358: // stop search on condition 3)
359: // if first comment fails, then there's no extended position in fact
360: if (idx == endIdx) {
361: return nodeStart;
362: }
363: break;
364: }
365: } catch (InvalidInputException e) {
366: // Should not happen, but return no extended position...
367: return nodeStart;
368: }
369: // verify that there's no more than one line between node/comments
370: char[] gap = this .scanner.getCurrentIdentifierSource();
371: int nbrLine = 0;
372: int pos = -1;
373: while ((pos = CharOperation.indexOf('\n', gap, pos + 1)) >= 0) {
374: nbrLine++;
375: }
376: if (nbrLine > 1) {
377: // stop search on condition 4)
378: break;
379: }
380: }
381: // Store previous infos
382: previousStart = commentStart;
383: startIdx = idx--;
384: }
385: if (startIdx != -1) {
386: // Verify that there's no token on the same line before first leading comment
387: int commentStart = this .comments[startIdx]
388: .getStartPosition();
389: if (previousEnd < commentStart
390: && previousEndLine != nodeStartLine) {
391: int lastTokenEnd = previousEnd;
392: this .scanner.resetTo(previousEnd, commentStart);
393: try {
394: while (this .scanner.currentPosition < commentStart) {
395: if (this .scanner.getNextToken() != TerminalTokens.TokenNameWHITESPACE) {
396: lastTokenEnd = this .scanner
397: .getCurrentTokenEndPosition();
398: }
399: }
400: } catch (InvalidInputException e) {
401: // do nothing
402: }
403: int lastTokenLine = getLineNumber(lastTokenEnd,
404: parentLineRange);
405: int length = this .comments.length;
406: while (startIdx < length
407: && lastTokenLine == getLineNumber(
408: this .comments[startIdx]
409: .getStartPosition(),
410: parentLineRange)
411: && nodeStartLine != lastTokenLine) {
412: startIdx++;
413: }
414: }
415: // Store leading comments indexes
416: if (startIdx <= endIdx) {
417: if (++this .leadingPtr == 0) {
418: this .leadingNodes = new ASTNode[STORAGE_INCREMENT];
419: this .leadingIndexes = new long[STORAGE_INCREMENT];
420: } else if (this .leadingPtr == this .leadingNodes.length) {
421: int newLength = (this .leadingPtr * 3 / 2)
422: + STORAGE_INCREMENT;
423: System.arraycopy(this .leadingNodes, 0,
424: this .leadingNodes = new ASTNode[newLength],
425: 0, this .leadingPtr);
426: System.arraycopy(this .leadingIndexes, 0,
427: this .leadingIndexes = new long[newLength],
428: 0, this .leadingPtr);
429: }
430: this .leadingNodes[this .leadingPtr] = node;
431: this .leadingIndexes[this .leadingPtr] = (((long) startIdx) << 32)
432: + endIdx;
433: extended = this .comments[endIdx].getStartPosition();
434: }
435: }
436: return extended;
437: }
438:
439: /**
440: * Search and store node trailing comments. Comments are searched in position range
441: * from node end position to specified next start. If one or several comment are found,
442: * returns last comment end position, otherwise returns node end position.
443: * <p>
444: * Starts to search for first comment after node end position and return if none was found...
445: *</p><p>
446: * When first comment is found after node, goes down in comment list until one of
447: * following conditions becomes true:
448: * <ol>
449: * <li>comment start is after next start</li>
450: * <li>there's other than white characters between current node and comment</li>
451: * <li>there's more than 1 line between current node and comment</li>
452: *</ol>
453: * If at least potential comments have been found, then all of them has to be separated
454: * from following node. So, remove all comments which do not verify this assumption.
455: * Note that this verification is not applicable on last node.
456: * </p><p>
457: * If finally there's still trailing comments, then stores indexes of the first and last one
458: * in trailing comments table.
459: */
460: int storeTrailingComments(ASTNode node, int nextStart,
461: boolean lastChild, int[] parentLineRange) {
462:
463: // Init extended position
464: int nodeEnd = node.getStartPosition() + node.getLength() - 1;
465: if (nodeEnd == nextStart) {
466: // special case for last child of its parent
467: if (++this .trailingPtr == 0) {
468: this .trailingNodes = new ASTNode[STORAGE_INCREMENT];
469: this .trailingIndexes = new long[STORAGE_INCREMENT];
470: this .lastTrailingPtr = -1;
471: } else if (this .trailingPtr == this .trailingNodes.length) {
472: int newLength = (this .trailingPtr * 3 / 2)
473: + STORAGE_INCREMENT;
474: System.arraycopy(this .trailingNodes, 0,
475: this .trailingNodes = new ASTNode[newLength], 0,
476: this .trailingPtr);
477: System.arraycopy(this .trailingIndexes, 0,
478: this .trailingIndexes = new long[newLength], 0,
479: this .trailingPtr);
480: }
481: this .trailingNodes[this .trailingPtr] = node;
482: this .trailingIndexes[this .trailingPtr] = -1;
483: return nodeEnd;
484: }
485: int extended = nodeEnd;
486:
487: // Get line number
488: int nodeEndLine = getLineNumber(nodeEnd, parentLineRange);
489:
490: // Find comments range index
491: int idx = getCommentIndex(0, nodeEnd, 1);
492: if (idx == -1) {
493: return nodeEnd;
494: }
495:
496: // Look after potential comments
497: int startIdx = idx;
498: int endIdx = -1;
499: int length = this .comments.length;
500: int commentStart = extended + 1;
501: int previousEnd = nodeEnd + 1;
502: int sameLineIdx = -1;
503: while (idx < length && commentStart < nextStart) {
504: // get comment and leave if next starting position has been reached
505: Comment comment = this .comments[idx];
506: commentStart = comment.getStartPosition();
507: // verify that there's nothing else than white spaces between node/comments
508: if (commentStart >= nextStart) {
509: // stop search on condition 1)
510: break;
511: } else if (previousEnd < commentStart) {
512: this .scanner.resetTo(previousEnd, commentStart);
513: try {
514: int token = this .scanner.getNextToken();
515: if (token != TerminalTokens.TokenNameWHITESPACE
516: || this .scanner.currentPosition != commentStart) {
517: // stop search on condition 2)
518: // if first index fails, then there's no extended position in fact...
519: if (idx == startIdx) {
520: return nodeEnd;
521: }
522: // otherwise we get the last index of trailing comment => break
523: break;
524: }
525: } catch (InvalidInputException e) {
526: // Should not happen, but return no extended position...
527: return nodeEnd;
528: }
529: // verify that there's no more than one line between node/comments
530: char[] gap = this .scanner.getCurrentIdentifierSource();
531: int nbrLine = 0;
532: int pos = -1;
533: while ((pos = CharOperation.indexOf('\n', gap, pos + 1)) >= 0) {
534: nbrLine++;
535: }
536: if (nbrLine > 1) {
537: // stop search on condition 3)
538: break;
539: }
540: }
541: // Store index if we're on the same line than node end
542: int commentLine = getLineNumber(commentStart,
543: parentLineRange);
544: if (commentLine == nodeEndLine) {
545: sameLineIdx = idx;
546: }
547: // Store previous infos
548: previousEnd = commentStart + comment.getLength();
549: endIdx = idx++;
550: }
551: if (endIdx != -1) {
552: // Verify that following node start is separated
553: if (!lastChild) {
554: int nextLine = getLineNumber(nextStart, parentLineRange);
555: int previousLine = getLineNumber(previousEnd,
556: parentLineRange);
557: if ((nextLine - previousLine) <= 1) {
558: if (sameLineIdx == -1)
559: return nodeEnd;
560: endIdx = sameLineIdx;
561: }
562: }
563: // Store trailing comments indexes
564: if (++this .trailingPtr == 0) {
565: this .trailingNodes = new ASTNode[STORAGE_INCREMENT];
566: this .trailingIndexes = new long[STORAGE_INCREMENT];
567: this .lastTrailingPtr = -1;
568: } else if (this .trailingPtr == this .trailingNodes.length) {
569: int newLength = (this .trailingPtr * 3 / 2)
570: + STORAGE_INCREMENT;
571: System.arraycopy(this .trailingNodes, 0,
572: this .trailingNodes = new ASTNode[newLength], 0,
573: this .trailingPtr);
574: System.arraycopy(this .trailingIndexes, 0,
575: this .trailingIndexes = new long[newLength], 0,
576: this .trailingPtr);
577: }
578: this .trailingNodes[this .trailingPtr] = node;
579: long nodeRange = (((long) startIdx) << 32) + endIdx;
580: this .trailingIndexes[this .trailingPtr] = nodeRange;
581: // Compute new extended end
582: extended = this .comments[endIdx].getStartPosition()
583: + this .comments[endIdx].getLength() - 1;
584: // Look for children unresolved extended end
585: ASTNode previousNode = node;
586: int ptr = this .trailingPtr - 1; // children extended end were stored before
587: while (ptr >= 0) {
588: long range = this .trailingIndexes[ptr];
589: if (range != -1)
590: break; // there's no more unresolved nodes
591: ASTNode unresolved = this .trailingNodes[ptr];
592: if (previousNode != unresolved.getParent())
593: break; // we're no longer in node ancestor hierarchy
594: this .trailingIndexes[ptr] = nodeRange;
595: previousNode = unresolved;
596: ptr--; // get previous node
597: }
598: // Remove remaining unresolved nodes
599: if (ptr > this .lastTrailingPtr) {
600: int offset = ptr - this .lastTrailingPtr;
601: for (int i = ptr + 1; i <= this .trailingPtr; i++) {
602: this .trailingNodes[i - offset] = this .trailingNodes[i];
603: this .trailingIndexes[i - offset] = this .trailingIndexes[i];
604: }
605: this .trailingPtr -= offset;
606: }
607: this .lastTrailingPtr = this .trailingPtr;
608: }
609: return extended;
610: }
611:
612: class CommentMapperVisitor extends DefaultASTVisitor {
613:
614: ASTNode topSiblingParent = null;
615: ASTNode[] siblings = new ASTNode[10];
616: int[][] parentLineRange = new int[10][];
617: int siblingPtr = -1;
618:
619: protected boolean visitNode(ASTNode node) {
620:
621: // Get default previous end
622: ASTNode parent = node.getParent();
623: int previousEnd = parent.getStartPosition();
624:
625: // Look for sibling node
626: ASTNode sibling = parent == this .topSiblingParent ? (ASTNode) this .siblings[this .siblingPtr]
627: : null;
628: if (sibling != null) {
629: // Found one previous sibling, so compute its trailing comments using current node start position
630: try {
631: previousEnd = storeTrailingComments(sibling, node
632: .getStartPosition(), false,
633: this .parentLineRange[this .siblingPtr]);
634: } catch (Exception ex) {
635: // Give up extended ranges at this level if unexpected exception happens...
636: }
637: }
638:
639: // Stop visit for malformed node (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=84049)
640: if ((node.typeAndFlags & ASTNode.MALFORMED) != 0) {
641: return false;
642: }
643:
644: // Compute leading comments for current node
645: int[] previousLineRange = this .siblingPtr > -1 ? this .parentLineRange[this .siblingPtr]
646: : new int[] {
647: 1,
648: DefaultCommentMapper.this .scanner.linePtr + 1 };
649: try {
650: storeLeadingComments(node, previousEnd,
651: previousLineRange);
652: } catch (Exception ex) {
653: // Give up extended ranges at this level if unexpected exception happens...
654: }
655:
656: // Store current node as waiting sibling for its parent
657: if (this .topSiblingParent != parent) {
658: if (this .siblings.length == ++this .siblingPtr) {
659: System
660: .arraycopy(
661: this .siblings,
662: 0,
663: this .siblings = new ASTNode[this .siblingPtr * 2],
664: 0, this .siblingPtr);
665: System
666: .arraycopy(
667: this .parentLineRange,
668: 0,
669: this .parentLineRange = new int[this .siblingPtr * 2][],
670: 0, this .siblingPtr);
671: }
672: if (this .topSiblingParent == null) {
673: // node is a CompilationUnit
674: this .parentLineRange[this .siblingPtr] = previousLineRange;
675: } else {
676: int parentStart = parent.getStartPosition();
677: int firstLine = getLineNumber(parentStart,
678: previousLineRange);
679: int lastLine = getLineNumber(parentStart
680: + parent.getLength() - 1, previousLineRange);
681: if (this .parentLineRange[this .siblingPtr] == null) {
682: this .parentLineRange[this .siblingPtr] = new int[] {
683: firstLine, lastLine };
684: } else {
685: int[] lineRange = this .parentLineRange[this .siblingPtr];
686: lineRange[0] = firstLine;
687: lineRange[1] = lastLine;
688: }
689: }
690: this .topSiblingParent = parent;
691: }
692: this .siblings[this .siblingPtr] = node;
693:
694: // We're always ok to visit sub-levels
695: return true;
696: }
697:
698: protected void endVisitNode(ASTNode node) {
699:
700: // Look if a child node is waiting for trailing comments computing
701: ASTNode sibling = this .topSiblingParent == node ? (ASTNode) this .siblings[this .siblingPtr]
702: : null;
703: if (sibling != null) {
704: try {
705: storeTrailingComments(sibling, node
706: .getStartPosition()
707: + node.getLength() - 1, true,
708: this .parentLineRange[this .siblingPtr]);
709: } catch (Exception ex) {
710: // Give up extended ranges at this level if unexpected exception happens...
711: }
712: }
713: // Remove sibling if needed
714: if (this .topSiblingParent != null /*not a CompilationUnit*/
715: && this .topSiblingParent == node) {
716: this .siblingPtr--;
717: this .topSiblingParent = node.getParent();
718: }
719: }
720:
721: public boolean visit(CompilationUnit node) {
722: // do nothing special, just go down in sub-levels
723: return true;
724: }
725: }
726: }
|