1 11 package org.eclipse.jdt.core.dom; 12 13 import org.eclipse.jdt.core.compiler.CharOperation; 14 import org.eclipse.jdt.core.compiler.InvalidInputException; 15 import org.eclipse.jdt.internal.compiler.parser.Scanner; 16 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; 17 import org.eclipse.jdt.internal.compiler.util.Util; 18 19 24 class DefaultCommentMapper { 25 Comment[] comments; 26 Scanner scanner; 27 28 int leadingPtr; 30 ASTNode[] leadingNodes; 31 long[] leadingIndexes; 32 int trailingPtr, lastTrailingPtr; 33 ASTNode[] trailingNodes; 34 long[] trailingIndexes; 35 static final int STORAGE_INCREMENT = 16; 36 37 40 DefaultCommentMapper(Comment[] table) { 41 this.comments = table; 42 } 43 44 boolean hasSameTable(Comment[] table) { 45 return this.comments == table; 46 } 47 48 54 Comment getComment(int position) { 55 56 if (this.comments == null) { 57 return null; 58 } 59 int size = this.comments.length; 60 if (size == 0) { 61 return null; 62 } 63 int index = getCommentIndex(0, position, 0); 64 if (index<0) { 65 return null; 66 } 67 return this.comments[index]; 68 } 69 70 77 private int getCommentIndex(int start, int position, int exact) { 78 if (position == 0) { 79 if (this.comments.length > 0 && this.comments[0].getStartPosition() == 0) { 80 return 0; 81 } 82 return -1; 83 } 84 int bottom = start, top = this.comments.length - 1; 85 int i = 0, index = -1; 86 Comment comment = null; 87 while (bottom <= top) { 88 i = bottom + (top - bottom) /2; 89 comment = this.comments[i]; 90 int commentStart = comment.getStartPosition(); 91 if (position < commentStart) { 92 top = i-1; 93 } else if (position >=(commentStart+comment.getLength())) { 94 bottom = i+1; 95 } else { 96 index = i; 97 break; 98 } 99 } 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 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) range = this.leadingIndexes[i]; 128 } 129 if (range >= 0) { 130 return this.comments[(int)(range>>32)].getStartPosition() ; 131 } 132 } 133 return node.getStartPosition(); 134 } 135 136 143 public final int getLineNumber(int position, int[] lineRange) { 144 int[] lineEnds = this.scanner.lineEnds; 145 int length = lineEnds.length; 146 return Util.getLineNumber(position, lineEnds, (lineRange[0] > length ? length : lineRange[0]) -1, (lineRange[1] > length ? length : lineRange[1]) - 1); 147 } 148 149 152 public int getExtendedEnd(ASTNode node) { 153 int end = node.getStartPosition() + node.getLength(); 154 if (this.trailingPtr >= 0) { 155 long range = -1; 156 for (int i=0; range<0 && i<=this.trailingPtr; i++) { 157 if (this.trailingNodes[i] == node) range = this.trailingIndexes[i]; 158 } 159 if (range >= 0) { 160 Comment lastComment = this.comments[(int) range]; 161 end = lastComment.getStartPosition() + lastComment.getLength(); 162 } 163 } 164 return end-1; 165 } 166 167 180 public int getExtendedLength(ASTNode node) { 181 return getExtendedEnd(node) - getExtendedStartPosition(node) + 1; 182 } 183 184 190 int firstLeadingCommentIndex(ASTNode node) { 191 if (this.leadingPtr >= 0) { 192 for (int i=0; i<=this.leadingPtr; i++) { 193 if (this.leadingNodes[i] == node) { 194 return (int) (this.leadingIndexes[i]>>32); 195 } 196 } 197 } 198 return -1; 199 } 200 201 207 int lastTrailingCommentIndex(ASTNode node) { 208 if (this.trailingPtr >= 0) { 209 for (int i=0; i<=this.trailingPtr; i++) { 210 if (this.trailingNodes[i] == node) { 211 return (int) this.trailingIndexes[i]; 212 } 213 } 214 } 215 return -1; 216 } 217 218 224 void initialize(CompilationUnit unit, Scanner sc) { 225 226 this.leadingPtr = -1; 228 this.trailingPtr = -1; 229 230 this.comments = unit.optionalCommentTable; 232 if (this.comments == null) { 233 return; 234 } 235 int size = this.comments.length; 236 if (size == 0) { 237 return; 238 } 239 240 this.scanner = sc; 242 this.scanner.tokenizeWhiteSpace = true; 243 244 DefaultASTVisitor commentVisitor = new CommentMapperVisitor(); 246 unit.accept(commentVisitor); 247 248 int leadingCount = this.leadingPtr + 1; 250 if (leadingCount > 0 && leadingCount < this.leadingIndexes.length) { 251 System.arraycopy(this.leadingNodes, 0, this.leadingNodes = new ASTNode[leadingCount], 0, leadingCount); 252 System.arraycopy(this.leadingIndexes, 0, this.leadingIndexes= new long[leadingCount], 0, leadingCount); 253 } 254 255 if (this.trailingPtr >= 0) { 257 while (this.trailingIndexes[this.trailingPtr] == -1) { 259 this.trailingPtr--; 260 if (this.trailingPtr < 0) { 261 this.trailingIndexes = null; 262 this.trailingNodes = null; 263 break; 264 } 265 } 266 267 int trailingCount = this.trailingPtr + 1; 269 if (trailingCount > 0 && trailingCount < this.trailingIndexes.length) { 270 System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[trailingCount], 0, trailingCount); 271 System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes= new long[trailingCount], 0, trailingCount); 272 } 273 } 274 275 this.scanner = null; 277 } 278 279 300 int storeLeadingComments(ASTNode node, int previousEnd, int[] parentLineRange) { 301 int nodeStart = node.getStartPosition(); 303 int extended = nodeStart; 304 305 int previousEndLine = getLineNumber(previousEnd, parentLineRange); 307 int nodeStartLine = getLineNumber(nodeStart, parentLineRange); 308 309 int idx = getCommentIndex(0, nodeStart, -1); 311 if (idx == -1) { 312 return nodeStart; 313 } 314 315 int startIdx = -1; 317 int endIdx = idx; 318 int previousStart = nodeStart; 319 while (idx >= 0 && previousStart >= previousEnd) { 320 Comment comment = this.comments[idx]; 322 int commentStart = comment.getStartPosition(); 323 int end = commentStart+comment.getLength()-1; 324 int commentLine = getLineNumber(commentStart, parentLineRange); 325 if (end <= previousEnd || (commentLine == previousEndLine && commentLine != nodeStartLine)) { 326 break; 328 } else if ((end+1) < previousStart) { this.scanner.resetTo(end+1, previousStart); 330 try { 331 int token = this.scanner.getNextToken(); 332 if (token != TerminalTokens.TokenNameWHITESPACE || this.scanner.currentPosition != previousStart) { 333 if (idx == endIdx) { 336 return nodeStart; 337 } 338 break; 339 } 340 } catch (InvalidInputException e) { 341 return nodeStart; 343 } 344 char[] gap = this.scanner.getCurrentIdentifierSource(); 346 int nbrLine = 0; 347 int pos = -1; 348 while ((pos=CharOperation.indexOf('\n', gap,pos+1)) >= 0) { 349 nbrLine++; 350 } 351 if (nbrLine > 1) { 352 break; 354 } 355 } 356 previousStart = commentStart; 358 startIdx = idx--; 359 } 360 if (startIdx != -1) { 361 int commentStart = this.comments[startIdx].getStartPosition(); 363 if (previousEnd < commentStart && previousEndLine != nodeStartLine) { 364 int lastTokenEnd = previousEnd; 365 this.scanner.resetTo(previousEnd, commentStart); 366 try { 367 while (this.scanner.currentPosition < commentStart) { 368 if (this.scanner.getNextToken() != TerminalTokens.TokenNameWHITESPACE) { 369 lastTokenEnd = this.scanner.getCurrentTokenEndPosition(); 370 } 371 } 372 } catch (InvalidInputException e) { 373 } 375 int lastTokenLine = getLineNumber(lastTokenEnd, parentLineRange); 376 int length = this.comments.length; 377 while (startIdx<length && lastTokenLine == getLineNumber(this.comments[startIdx].getStartPosition(), parentLineRange) && nodeStartLine != lastTokenLine) { 378 startIdx++; 379 } 380 } 381 if (startIdx <= endIdx) { 383 if (++this.leadingPtr == 0) { 384 this.leadingNodes = new ASTNode[STORAGE_INCREMENT]; 385 this.leadingIndexes = new long[STORAGE_INCREMENT]; 386 } else if (this.leadingPtr == this.leadingNodes.length) { 387 int newLength = (this.leadingPtr*3/2)+STORAGE_INCREMENT; 388 System.arraycopy(this.leadingNodes, 0, this.leadingNodes = new ASTNode[newLength], 0, this.leadingPtr); 389 System.arraycopy(this.leadingIndexes, 0, this.leadingIndexes = new long[newLength], 0, this.leadingPtr); 390 } 391 this.leadingNodes[this.leadingPtr] = node; 392 this.leadingIndexes[this.leadingPtr] = (((long)startIdx)<<32) + endIdx; 393 extended = this.comments[endIdx].getStartPosition(); 394 } 395 } 396 return extended; 397 } 398 399 420 int storeTrailingComments(ASTNode node, int nextStart, boolean lastChild, int[] parentLineRange) { 421 422 int nodeEnd = node.getStartPosition()+node.getLength()-1; 424 if (nodeEnd == nextStart) { 425 if (++this.trailingPtr == 0) { 427 this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; 428 this.trailingIndexes = new long[STORAGE_INCREMENT]; 429 this.lastTrailingPtr = -1; 430 } else if (this.trailingPtr == this.trailingNodes.length) { 431 int newLength = (this.trailingPtr*3/2)+STORAGE_INCREMENT; 432 System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); 433 System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); 434 } 435 this.trailingNodes[this.trailingPtr] = node; 436 this.trailingIndexes[this.trailingPtr] = -1; 437 return nodeEnd; 438 } 439 int extended = nodeEnd; 440 441 int nodeEndLine = getLineNumber(nodeEnd, parentLineRange); 443 444 int idx = getCommentIndex(0, nodeEnd, 1); 446 if (idx == -1) { 447 return nodeEnd; 448 } 449 450 int startIdx = idx; 452 int endIdx = -1; 453 int length = this.comments.length; 454 int commentStart = extended+1; 455 int previousEnd = nodeEnd+1; 456 int sameLineIdx = -1; 457 while (idx<length && commentStart < nextStart) { 458 Comment comment = this.comments[idx]; 460 commentStart = comment.getStartPosition(); 461 if (commentStart >= nextStart) { 463 break; 465 } else if (previousEnd < commentStart) { 466 this.scanner.resetTo(previousEnd, commentStart); 467 try { 468 int token = this.scanner.getNextToken(); 469 if (token != TerminalTokens.TokenNameWHITESPACE || this.scanner.currentPosition != commentStart) { 470 if (idx == startIdx) { 473 return nodeEnd; 474 } 475 break; 477 } 478 } catch (InvalidInputException e) { 479 return nodeEnd; 481 } 482 char[] gap = this.scanner.getCurrentIdentifierSource(); 484 int nbrLine = 0; 485 int pos = -1; 486 while ((pos=CharOperation.indexOf('\n', gap,pos+1)) >= 0) { 487 nbrLine++; 488 } 489 if (nbrLine > 1) { 490 break; 492 } 493 } 494 int commentLine = getLineNumber(commentStart, parentLineRange); 496 if (commentLine == nodeEndLine) { 497 sameLineIdx = idx; 498 } 499 previousEnd = commentStart+comment.getLength(); 501 endIdx = idx++; 502 } 503 if (endIdx != -1) { 504 if (!lastChild) { 506 int nextLine = getLineNumber(nextStart, parentLineRange); 507 int previousLine = getLineNumber(previousEnd, parentLineRange); 508 if((nextLine - previousLine) <= 1) { 509 if (sameLineIdx == -1) return nodeEnd; 510 endIdx = sameLineIdx; 511 } 512 } 513 if (++this.trailingPtr == 0) { 515 this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; 516 this.trailingIndexes = new long[STORAGE_INCREMENT]; 517 this.lastTrailingPtr = -1; 518 } else if (this.trailingPtr == this.trailingNodes.length) { 519 int newLength = (this.trailingPtr*3/2)+STORAGE_INCREMENT; 520 System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); 521 System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); 522 } 523 this.trailingNodes[this.trailingPtr] = node; 524 long nodeRange = (((long)startIdx)<<32) + endIdx; 525 this.trailingIndexes[this.trailingPtr] = nodeRange; 526 extended = this.comments[endIdx].getStartPosition()+this.comments[endIdx].getLength()-1; 528 ASTNode previousNode = node; 530 int ptr = this.trailingPtr - 1; while (ptr >= 0) { 532 long range = this.trailingIndexes[ptr]; 533 if (range != -1) break; ASTNode unresolved = this.trailingNodes[ptr]; 535 if (previousNode != unresolved.getParent()) break; this.trailingIndexes[ptr] = nodeRange; 537 previousNode = unresolved; 538 ptr--; } 540 if (ptr > this.lastTrailingPtr) { 542 int offset = ptr - this.lastTrailingPtr; 543 for (int i=ptr+1; i<=this.trailingPtr; i++) { 544 this.trailingNodes[i-offset] = this.trailingNodes[i]; 545 this.trailingIndexes[i-offset] = this.trailingIndexes[i]; 546 } 547 this.trailingPtr -= offset; 548 } 549 this.lastTrailingPtr = this.trailingPtr; 550 } 551 return extended; 552 } 553 554 class CommentMapperVisitor extends DefaultASTVisitor { 555 556 ASTNode topSiblingParent = null; 557 ASTNode[] siblings = new ASTNode[10]; 558 int[][] parentLineRange = new int[10][]; 559 int siblingPtr = -1; 560 561 protected boolean visitNode(ASTNode node) { 562 563 ASTNode parent = node.getParent(); 565 int previousEnd = parent.getStartPosition(); 566 567 ASTNode sibling = parent == this.topSiblingParent ? (ASTNode) this.siblings[this.siblingPtr] : null; 569 if (sibling != null) { 570 try { 572 previousEnd = storeTrailingComments(sibling, node.getStartPosition(), false, this.parentLineRange[this.siblingPtr]); 573 } catch (Exception ex) { 574 } 576 } 577 578 if ((node.typeAndFlags & ASTNode.MALFORMED) != 0) { 580 return false; 581 } 582 583 int[] previousLineRange = this.siblingPtr > -1 ? this.parentLineRange[this.siblingPtr] : new int[] {1, DefaultCommentMapper.this.scanner.linePtr+1}; 585 try { 586 storeLeadingComments(node, previousEnd, previousLineRange); 587 } catch (Exception ex) { 588 } 590 591 if (this.topSiblingParent != parent) { 593 if (this.siblings.length == ++this.siblingPtr) { 594 System.arraycopy(this.siblings, 0, this.siblings = new ASTNode[this.siblingPtr*2], 0, this.siblingPtr); 595 System.arraycopy(this.parentLineRange, 0, this.parentLineRange = new int[this.siblingPtr*2][], 0, this.siblingPtr); 596 } 597 if (this.topSiblingParent == null) { 598 this.parentLineRange[this.siblingPtr] = previousLineRange; 600 } else { 601 int parentStart = parent.getStartPosition(); 602 int firstLine = getLineNumber(parentStart, previousLineRange); 603 int lastLine = getLineNumber(parentStart + parent.getLength() - 1, previousLineRange); 604 if (this.parentLineRange[this.siblingPtr] == null) { 605 this.parentLineRange[this.siblingPtr] = new int[] {firstLine, lastLine}; 606 } else { 607 int[] lineRange = this.parentLineRange[this.siblingPtr]; 608 lineRange[0] = firstLine; 609 lineRange[1] = lastLine; 610 } 611 } 612 this.topSiblingParent = parent; 613 } 614 this.siblings[this.siblingPtr] = node; 615 616 return true; 618 } 619 620 protected void endVisitNode(ASTNode node) { 621 622 ASTNode sibling = this.topSiblingParent == node ? (ASTNode) this.siblings[this.siblingPtr] : null; 624 if (sibling != null) { 625 try { 626 storeTrailingComments(sibling, node.getStartPosition()+node.getLength()-1, true, this.parentLineRange[this.siblingPtr]); 627 } catch (Exception ex) { 628 } 630 } 631 if (this.topSiblingParent != null 633 && this.topSiblingParent == node) { 634 this.siblingPtr--; 635 this.topSiblingParent = node.getParent(); 636 } 637 } 638 639 public boolean visit ( CompilationUnit node) { 640 return true; 642 } 643 } 644 } 645 | Popular Tags |