1 11 package org.eclipse.jdt.core.dom; 12 13 import java.util.Iterator ; 14 import java.util.List ; 15 16 import org.eclipse.jdt.core.compiler.CharOperation; 17 import org.eclipse.jdt.core.compiler.InvalidInputException; 18 import org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser; 19 import org.eclipse.jdt.internal.compiler.parser.Scanner; 20 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; 21 22 27 class DocCommentParser extends AbstractCommentParser { 28 29 31 private Javadoc docComment; 33 private AST ast; 34 35 DocCommentParser(AST ast, Scanner scanner, boolean check) { 36 super(null); 37 this.ast = ast; 38 this.scanner = scanner; 39 this.jdk15 = this.ast.apiLevel() >= AST.JLS3; 40 this.checkDocComment = check; 41 this.kind = DOM_PARSER; 42 } 43 44 50 public Javadoc parse(int[] positions) { 51 return parse(positions[0], positions[1]-positions[0]); 52 } 53 public Javadoc parse(int start, int length) { 54 55 this.source = this.scanner.source; 57 this.lineEnds = this.scanner.lineEnds; 58 this.docComment = new Javadoc(this.ast); 59 60 if (this.checkDocComment) { 62 this.javadocStart = start; 63 this.javadocEnd = start+length-1; 64 this.firstTagPosition = this.javadocStart; 65 commentParse(); 66 } 67 this.docComment.setSourceRange(start, length); 68 if (this.ast.apiLevel == AST.JLS2_INTERNAL) { 69 setComment(start, length); } 71 return this.docComment; 72 } 73 74 80 private void setComment(int start, int length) { 81 this.docComment.setComment(new String (this.source, start, length)); 82 } 83 84 public String toString() { 85 StringBuffer buffer = new StringBuffer (); 86 buffer.append("javadoc: ").append(this.docComment).append("\n"); buffer.append(super.toString()); 88 return buffer.toString(); 89 } 90 91 94 protected Object createArgumentReference(char[] name, int dim, boolean isVarargs, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException { 95 try { 96 MethodRefParameter argument = this.ast.newMethodRefParameter(); 97 ASTNode node = (ASTNode) typeRef; 98 int argStart = node.getStartPosition(); 99 int argEnd = node.getStartPosition()+node.getLength()-1; 100 if (dim > 0) argEnd = (int) dimPositions[dim-1]; 101 if (argNamePos >= 0) argEnd = (int) argNamePos; 102 if (name.length != 0) { 103 final SimpleName argName = new SimpleName(this.ast); 104 argName.internalSetIdentifier(new String (name)); 105 argument.setName(argName); 106 int argNameStart = (int) (argNamePos >>> 32); 107 argName.setSourceRange(argNameStart, argEnd-argNameStart+1); 108 } 109 Type argType = null; 110 if (node.getNodeType() == ASTNode.PRIMITIVE_TYPE) { 111 argType = (PrimitiveType) node; 112 } else { 117 Name argTypeName = (Name) node; 118 argType = this.ast.newSimpleType(argTypeName); 119 argType.setSourceRange(argStart, node.getLength()); 120 } 121 if (dim > 0 && !isVarargs) { 122 for (int i=0; i<dim; i++) { 123 argType = this.ast.newArrayType(argType); 124 argType.setSourceRange(argStart, ((int) dimPositions[i])-argStart+1); 125 } 126 } 127 argument.setType(argType); 128 argument.setSourceRange(argStart, argEnd - argStart + 1); 129 return argument; 130 } 131 catch (ClassCastException ex) { 132 throw new InvalidInputException(); 133 } 134 } 135 138 protected Object createFieldReference(Object receiver) throws InvalidInputException { 139 try { 140 MemberRef fieldRef = this.ast.newMemberRef(); 141 SimpleName fieldName = new SimpleName(this.ast); 142 fieldName.internalSetIdentifier(new String (this.identifierStack[0])); 143 fieldRef.setName(fieldName); 144 int start = (int) (this.identifierPositionStack[0] >>> 32); 145 int end = (int) this.identifierPositionStack[0]; 146 fieldName.setSourceRange(start, end - start + 1); 147 if (receiver == null) { 148 start = this.memberStart; 149 fieldRef.setSourceRange(start, end - start + 1); 150 } else { 151 Name typeRef = (Name) receiver; 152 fieldRef.setQualifier(typeRef); 153 start = typeRef.getStartPosition(); 154 end = fieldName.getStartPosition()+fieldName.getLength()-1; 155 fieldRef.setSourceRange(start, end-start+1); 156 } 157 return fieldRef; 158 } 159 catch (ClassCastException ex) { 160 throw new InvalidInputException(); 161 } 162 } 163 166 protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException { 167 try { 168 MethodRef methodRef = this.ast.newMethodRef(); 170 SimpleName methodName = new SimpleName(this.ast); 171 methodName.internalSetIdentifier(new String (this.identifierStack[0])); 172 methodRef.setName(methodName); 173 int start = (int) (this.identifierPositionStack[0] >>> 32); 174 int end = (int) this.identifierPositionStack[0]; 175 methodName.setSourceRange(start, end - start + 1); 176 if (receiver == null) { 179 start = this.memberStart; 180 methodRef.setSourceRange(start, end - start + 1); 181 } else { 182 Name typeRef = (Name) receiver; 183 methodRef.setQualifier(typeRef); 184 start = typeRef.getStartPosition(); 185 } 186 if (arguments != null) { 188 Iterator parameters = arguments.listIterator(); 189 while (parameters.hasNext()) { 190 MethodRefParameter param = (MethodRefParameter) parameters.next(); 191 methodRef.parameters().add(param); 192 } 194 } 195 methodRef.setSourceRange(start, this.scanner.getCurrentTokenEndPosition()-start+1); 197 return methodRef; 198 } 199 catch (ClassCastException ex) { 200 throw new InvalidInputException(); 201 } 202 } 203 204 207 protected void createTag() { 208 TagElement tagElement = this.ast.newTagElement(); 209 int start = this.tagSourceStart; 210 String tagName = new String (this.source, start, this.tagSourceEnd-start+1); 211 switch (tagName.charAt(0)) { 212 case 'a': 213 if (tagName.equals(TagElement.TAG_AUTHOR)) { 214 tagName = TagElement.TAG_AUTHOR; 215 } 216 break; 217 case 'd': 218 if (tagName.equals(TagElement.TAG_DOCROOT)) { 219 tagName = TagElement.TAG_DOCROOT; 220 } 221 break; 222 case 'r': 223 if (tagName.equals(TagElement.TAG_RETURN)) { 224 tagName = TagElement.TAG_RETURN; 225 } 226 break; 227 case 's': 228 if (tagName.equals(TagElement.TAG_SERIAL)) { 229 tagName = TagElement.TAG_SERIAL; 230 } else if (tagName.equals(TagElement.TAG_SERIALDATA)) { 231 tagName = TagElement.TAG_SERIALDATA; 232 } else if (tagName.equals(TagElement.TAG_SERIALFIELD)) { 233 tagName = TagElement.TAG_SERIALFIELD; 234 } 235 break; 236 case 'v': 237 if (tagName.equals(TagElement.TAG_VERSION)) { 238 tagName = TagElement.TAG_VERSION; 239 } 240 break; 241 } 242 tagElement.setTagName(tagName); 243 if (this.inlineTagStarted) { 244 start = this.inlineTagStart; 245 TagElement previousTag = null; 246 if (this.astPtr == -1) { 247 previousTag = this.ast.newTagElement(); 248 previousTag.setSourceRange(start, this.tagSourceEnd-start+1); 249 pushOnAstStack(previousTag, true); 250 } else { 251 previousTag = (TagElement) this.astStack[this.astPtr]; 252 } 253 int previousStart = previousTag.getStartPosition(); 254 previousTag.fragments().add(tagElement); 255 previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1); 256 } else { 257 pushOnAstStack(tagElement, true); 258 } 259 tagElement.setSourceRange(start, this.tagSourceEnd-start+1); 260 } 262 263 266 protected Object createTypeReference(int primitiveToken) { 267 int size = this.identifierLengthStack[this.identifierLengthPtr--]; 268 String [] identifiers = new String [size]; 269 int pos = this.identifierPtr - size + 1; 270 for (int i = 0; i < size; i++) { 271 identifiers[i] = new String (this.identifierStack[pos+i]); 272 } 273 ASTNode typeRef = null; 274 if (primitiveToken == -1) { 275 typeRef = this.ast.internalNewName(identifiers); 276 } else { 277 switch (primitiveToken) { 278 case TerminalTokens.TokenNamevoid : 279 typeRef = this.ast.newPrimitiveType(PrimitiveType.VOID); 280 break; 281 case TerminalTokens.TokenNameboolean : 282 typeRef = this.ast.newPrimitiveType(PrimitiveType.BOOLEAN); 283 break; 284 case TerminalTokens.TokenNamebyte : 285 typeRef = this.ast.newPrimitiveType(PrimitiveType.BYTE); 286 break; 287 case TerminalTokens.TokenNamechar : 288 typeRef = this.ast.newPrimitiveType(PrimitiveType.CHAR); 289 break; 290 case TerminalTokens.TokenNamedouble : 291 typeRef = this.ast.newPrimitiveType(PrimitiveType.DOUBLE); 292 break; 293 case TerminalTokens.TokenNamefloat : 294 typeRef = this.ast.newPrimitiveType(PrimitiveType.FLOAT); 295 break; 296 case TerminalTokens.TokenNameint : 297 typeRef = this.ast.newPrimitiveType(PrimitiveType.INT); 298 break; 299 case TerminalTokens.TokenNamelong : 300 typeRef = this.ast.newPrimitiveType(PrimitiveType.LONG); 301 break; 302 case TerminalTokens.TokenNameshort : 303 typeRef = this.ast.newPrimitiveType(PrimitiveType.SHORT); 304 break; 305 default: 306 return null; 308 } 309 } 310 int start = (int) (this.identifierPositionStack[pos] >>> 32); 312 if (size > 1) { 316 Name name = (Name)typeRef; 317 int nameIndex = size; 318 for (int i=this.identifierPtr; i>pos; i--, nameIndex--) { 319 int s = (int) (this.identifierPositionStack[i] >>> 32); 320 int e = (int) this.identifierPositionStack[i]; 321 name.index = nameIndex; 322 SimpleName simpleName = ((QualifiedName)name).getName(); 323 simpleName.index = nameIndex; 324 simpleName.setSourceRange(s, e-s+1); 325 name.setSourceRange(start, e-start+1); 326 name = ((QualifiedName)name).getQualifier(); 327 } 328 int end = (int) this.identifierPositionStack[pos]; 329 name.setSourceRange(start, end-start+1); 330 name.index = nameIndex; 331 } else { 332 int end = (int) this.identifierPositionStack[pos]; 333 typeRef.setSourceRange(start, end-start+1); 334 } 335 this.identifierPtr -= size; 336 return typeRef; 337 } 338 339 342 protected boolean parseReturn() { 343 createTag(); 344 return true; 345 } 346 347 350 protected boolean parseTag(int previousPosition) throws InvalidInputException { 351 352 int token = readTokenAndConsume(); 354 this.tagSourceStart = this.scanner.getCurrentTokenStartPosition(); 355 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition(); 356 357 int tk = token; 360 char pc = peekChar(); 361 tagNameToken: while (tk != TerminalTokens.TokenNameEOF) { 362 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition(); 363 token = tk; 364 switch (pc) { 366 case '}': 367 case '!': 368 case '#': 369 case '%': 370 case '&': 371 case '\'': 372 case '"': 373 case ':': 374 case '<': 376 case '>': 377 case '*': break tagNameToken; 379 default: 380 if (pc == ' ' || Character.isWhitespace(pc)) break tagNameToken; 381 } 382 tk = readTokenAndConsume(); 383 pc = peekChar(); 384 } 385 int length = this.tagSourceEnd-this.tagSourceStart+1; 386 char[] tag = new char[length]; 387 System.arraycopy(this.source, this.tagSourceStart, tag, 0, length); 388 this.index = this.tagSourceEnd+1; 389 this.scanner.currentPosition = this.tagSourceEnd+1; 390 this.tagSourceStart = previousPosition; 391 392 this.tagValue = NO_TAG_VALUE; 394 boolean valid = true; 395 switch (token) { 396 case TerminalTokens.TokenNameIdentifier : 397 switch (tag[0]) { 398 case 'd': 399 if (CharOperation.equals(tag, TAG_DEPRECATED)) { 400 this.deprecated = true; 401 this.tagValue = TAG_DEPRECATED_VALUE; 402 } else { 403 this.tagValue = TAG_OTHERS_VALUE; 404 } 405 createTag(); 406 break; 407 case 'i': 408 if (CharOperation.equals(tag, TAG_INHERITDOC)) { 409 if (this.astPtr==-1) { 415 this.inheritedPositions = (((long) this.tagSourceStart) << 32) + this.tagSourceEnd; 416 } 417 this.tagValue = TAG_INHERITDOC_VALUE; 418 } else { 419 this.tagValue = TAG_OTHERS_VALUE; 420 } 421 createTag(); 422 break; 423 case 'p': 424 if (CharOperation.equals(tag, TAG_PARAM)) { 425 this.tagValue = TAG_PARAM_VALUE; 426 valid = parseParam(); 427 } else { 428 this.tagValue = TAG_OTHERS_VALUE; 429 createTag(); 430 } 431 break; 432 case 'e': 433 if (CharOperation.equals(tag, TAG_EXCEPTION)) { 434 this.tagValue = TAG_EXCEPTION_VALUE; 435 valid = parseThrows(); 436 } else { 437 this.tagValue = TAG_OTHERS_VALUE; 438 createTag(); 439 } 440 break; 441 case 's': 442 if (CharOperation.equals(tag, TAG_SEE)) { 443 this.tagValue = TAG_SEE_VALUE; 444 if (this.inlineTagStarted) { 445 valid = false; 448 } else { 449 valid = parseReference(); 450 } 451 } else { 452 this.tagValue = TAG_OTHERS_VALUE; 453 createTag(); 454 } 455 break; 456 case 'l': 457 if (CharOperation.equals(tag, TAG_LINK)) { 458 this.tagValue = TAG_LINK_VALUE; 459 } else if (CharOperation.equals(tag, TAG_LINKPLAIN)) { 460 this.tagValue = TAG_LINKPLAIN_VALUE; 461 } 462 if (this.tagValue != NO_TAG_VALUE) { 463 if (this.inlineTagStarted) { 464 valid = parseReference(); 465 } else { 466 valid = false; 469 } 470 } else { 471 this.tagValue = TAG_OTHERS_VALUE; 472 createTag(); 473 } 474 break; 475 case 'v': 476 if (this.jdk15 && CharOperation.equals(tag, TAG_VALUE)) { 477 this.tagValue = TAG_VALUE_VALUE; 478 if (this.inlineTagStarted) { 479 valid = parseReference(); 480 } else { 481 valid = false; 482 } 483 } else { 484 this.tagValue = TAG_OTHERS_VALUE; 485 createTag(); 486 } 487 break; 488 default: 489 this.tagValue = TAG_OTHERS_VALUE; 490 createTag(); 491 } 492 break; 493 case TerminalTokens.TokenNamereturn : 494 this.tagValue = TAG_RETURN_VALUE; 495 valid = parseReturn(); 496 break; 497 case TerminalTokens.TokenNamethrows : 498 this.tagValue = TAG_THROWS_VALUE; 499 valid = parseThrows(); 500 break; 501 case TerminalTokens.TokenNameabstract: 502 case TerminalTokens.TokenNameassert: 503 case TerminalTokens.TokenNameboolean: 504 case TerminalTokens.TokenNamebreak: 505 case TerminalTokens.TokenNamebyte: 506 case TerminalTokens.TokenNamecase: 507 case TerminalTokens.TokenNamecatch: 508 case TerminalTokens.TokenNamechar: 509 case TerminalTokens.TokenNameclass: 510 case TerminalTokens.TokenNamecontinue: 511 case TerminalTokens.TokenNamedefault: 512 case TerminalTokens.TokenNamedo: 513 case TerminalTokens.TokenNamedouble: 514 case TerminalTokens.TokenNameelse: 515 case TerminalTokens.TokenNameextends: 516 case TerminalTokens.TokenNamefalse: 517 case TerminalTokens.TokenNamefinal: 518 case TerminalTokens.TokenNamefinally: 519 case TerminalTokens.TokenNamefloat: 520 case TerminalTokens.TokenNamefor: 521 case TerminalTokens.TokenNameif: 522 case TerminalTokens.TokenNameimplements: 523 case TerminalTokens.TokenNameimport: 524 case TerminalTokens.TokenNameinstanceof: 525 case TerminalTokens.TokenNameint: 526 case TerminalTokens.TokenNameinterface: 527 case TerminalTokens.TokenNamelong: 528 case TerminalTokens.TokenNamenative: 529 case TerminalTokens.TokenNamenew: 530 case TerminalTokens.TokenNamenull: 531 case TerminalTokens.TokenNamepackage: 532 case TerminalTokens.TokenNameprivate: 533 case TerminalTokens.TokenNameprotected: 534 case TerminalTokens.TokenNamepublic: 535 case TerminalTokens.TokenNameshort: 536 case TerminalTokens.TokenNamestatic: 537 case TerminalTokens.TokenNamestrictfp: 538 case TerminalTokens.TokenNamesuper: 539 case TerminalTokens.TokenNameswitch: 540 case TerminalTokens.TokenNamesynchronized: 541 case TerminalTokens.TokenNamethis: 542 case TerminalTokens.TokenNamethrow: 543 case TerminalTokens.TokenNametransient: 544 case TerminalTokens.TokenNametrue: 545 case TerminalTokens.TokenNametry: 546 case TerminalTokens.TokenNamevoid: 547 case TerminalTokens.TokenNamevolatile: 548 case TerminalTokens.TokenNamewhile: 549 this.tagValue = TAG_OTHERS_VALUE; 550 createTag(); 551 break; 552 } 553 this.textStart = this.index; 554 return valid; 555 } 556 557 560 protected boolean pushParamName(boolean isTypeParam) { 561 int idIndex = isTypeParam ? 1 : 0; 562 final SimpleName name = new SimpleName(this.ast); 563 name.internalSetIdentifier(new String (this.identifierStack[idIndex])); 564 int nameStart = (int) (this.identifierPositionStack[idIndex] >>> 32); 565 int nameEnd = (int) (this.identifierPositionStack[idIndex] & 0x00000000FFFFFFFFL); 566 name.setSourceRange(nameStart, nameEnd-nameStart+1); 567 TagElement paramTag = this.ast.newTagElement(); 568 paramTag.setTagName(TagElement.TAG_PARAM); 569 if (isTypeParam) { TextElement text = this.ast.newTextElement(); 572 text.setText(new String (this.identifierStack[0])); 573 int txtStart = (int) (this.identifierPositionStack[0] >>> 32); 574 int txtEnd = (int) (this.identifierPositionStack[0] & 0x00000000FFFFFFFFL); 575 text.setSourceRange(txtStart, txtEnd-txtStart+1); 576 paramTag.fragments().add(text); 577 paramTag.fragments().add(name); 579 text = this.ast.newTextElement(); 581 text.setText(new String (this.identifierStack[2])); 582 txtStart = (int) (this.identifierPositionStack[2] >>> 32); 583 txtEnd = (int) (this.identifierPositionStack[2] & 0x00000000FFFFFFFFL); 584 text.setSourceRange(txtStart, txtEnd-txtStart+1); 585 paramTag.fragments().add(text); 586 paramTag.setSourceRange(this.tagSourceStart, txtEnd-this.tagSourceStart+1); 588 } else { 589 paramTag.setSourceRange(this.tagSourceStart, nameEnd-this.tagSourceStart+1); 590 paramTag.fragments().add(name); 591 } 592 pushOnAstStack(paramTag, true); 593 return true; 594 } 595 598 protected boolean pushSeeRef(Object statement) { 599 TagElement seeTag = this.ast.newTagElement(); 600 ASTNode node = (ASTNode) statement; 601 seeTag.fragments().add(node); 602 int end = node.getStartPosition()+node.getLength()-1; 603 if (this.inlineTagStarted) { 604 seeTag.setSourceRange(this.inlineTagStart, end-this.inlineTagStart+1); 605 switch (this.tagValue) { 606 case TAG_LINK_VALUE: 607 seeTag.setTagName(TagElement.TAG_LINK); 608 break; 609 case TAG_LINKPLAIN_VALUE: 610 seeTag.setTagName(TagElement.TAG_LINKPLAIN); 611 break; 612 case TAG_VALUE_VALUE: 613 seeTag.setTagName(TagElement.TAG_VALUE); 614 break; 615 } 616 TagElement previousTag = null; 617 int previousStart = this.inlineTagStart; 618 if (this.astPtr == -1) { 619 previousTag = this.ast.newTagElement(); 620 pushOnAstStack(previousTag, true); 621 } else { 622 previousTag = (TagElement) this.astStack[this.astPtr]; 623 previousStart = previousTag.getStartPosition(); 624 } 625 previousTag.fragments().add(seeTag); 626 previousTag.setSourceRange(previousStart, end-previousStart+1); 627 } else { 628 seeTag.setTagName(TagElement.TAG_SEE); 629 seeTag.setSourceRange(this.tagSourceStart, end-this.tagSourceStart+1); 630 pushOnAstStack(seeTag, true); 631 } 632 return true; 633 } 634 637 protected void pushText(int start, int end) { 638 TextElement text = this.ast.newTextElement(); 639 text.setText(new String ( this.source, start, end-start)); 640 text.setSourceRange(start, end-start); 641 TagElement previousTag = null; 642 int previousStart = start; 643 if (this.astPtr == -1) { 644 previousTag = this.ast.newTagElement(); 645 previousTag.setSourceRange(start, end-start); 646 pushOnAstStack(previousTag, true); 647 } else { 648 previousTag = (TagElement) this.astStack[this.astPtr]; 649 previousStart = previousTag.getStartPosition(); 650 } 651 if (this.inlineTagStarted) { 652 if (previousTag.fragments().size() == 0) { 653 TagElement inlineTag = this.ast.newTagElement(); 654 previousTag.fragments().add(inlineTag); 655 previousTag = inlineTag; 656 } else { 657 ASTNode inlineTag = (ASTNode) previousTag.fragments().get(previousTag.fragments().size()-1); 658 if (inlineTag.getNodeType() == ASTNode.TAG_ELEMENT) { 659 previousTag = (TagElement) inlineTag; 660 previousStart = previousTag.getStartPosition(); 661 } 662 } 663 } 664 previousTag.fragments().add(text); 665 previousTag.setSourceRange(previousStart, end-previousStart); 666 this.textStart = -1; 667 } 668 671 protected void refreshInlineTagPosition(int previousPosition) { 672 if (this.astPtr != -1) { 673 TagElement previousTag = (TagElement) this.astStack[this.astPtr]; 674 if (this.inlineTagStarted) { 675 int previousStart = previousTag.getStartPosition(); 676 previousTag.setSourceRange(previousStart, previousPosition-previousStart+1); 677 if (previousTag.fragments().size() > 0) { 678 ASTNode inlineTag = (ASTNode) previousTag.fragments().get(previousTag.fragments().size()-1); 679 if (inlineTag.getNodeType() == ASTNode.TAG_ELEMENT) { 680 int inlineStart = inlineTag.getStartPosition(); 681 inlineTag.setSourceRange(inlineStart, previousPosition-inlineStart+1); 682 } 683 } 684 } 685 } 686 } 687 690 protected boolean pushThrowName(Object typeRef) { 691 TagElement throwsTag = this.ast.newTagElement(); 692 switch (this.tagValue) { 693 case TAG_THROWS_VALUE: 694 throwsTag.setTagName(TagElement.TAG_THROWS); 695 break; 696 case TAG_EXCEPTION_VALUE: 697 throwsTag.setTagName(TagElement.TAG_EXCEPTION); 698 break; 699 } 700 throwsTag.setSourceRange(this.tagSourceStart, this.scanner.getCurrentTokenEndPosition()-this.tagSourceStart+1); 701 throwsTag.fragments().add(typeRef); 702 pushOnAstStack(throwsTag, true); 703 return true; 704 } 705 706 709 protected void updateDocComment() { 710 for (int idx = 0; idx <= this.astPtr; idx++) { 711 this.docComment.tags().add(this.astStack[idx]); 712 } 713 } 714 } 715 | Popular Tags |