1 /*******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
13 import java.util.Iterator;
14 import java.util.List;
16 import net.sourceforge.phpdt.core.compiler.CharOperation;
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileConstants;
19 import net.sourceforge.phpdt.internal.compiler.parser.AbstractCommentParser;
20 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
21 import net.sourceforge.phpdt.internal.compiler.parser.ScannerHelper;
22 import net.sourceforge.phpdt.internal.compiler.parser.TerminalTokens;
25 * Internal parser used for decoding doc comments.
29 class DocCommentParser extends AbstractCommentParser {
31 private Javadoc docComment;
34 DocCommentParser(AST ast, Scanner scanner, boolean check) {
37 this.scanner = scanner;
38 this.sourceLevel = this.ast.apiLevel() >= AST.JLS3 ? ClassFileConstants.JDK1_5 : ClassFileConstants.JDK1_3;
39 this.checkDocComment = check;
40 this.kind = DOM_PARSER | TEXT_PARSE;
44 * Returns true if tag @deprecated is present in annotation.
46 * If annotation checking is enabled, will also construct an Annotation node, which will be stored into Parser.annotation
47 * slot for being consumed later on.
49 public Javadoc parse(int[] positions) {
50 return parse(positions[0], positions[1]-positions[0]);
52 public Javadoc parse(int start, int length) {
55 this.source = this.scanner.source;
56 this.lineEnds = this.scanner.lineEnds;
57 this.docComment = new Javadoc(this.ast);
60 if (this.checkDocComment) {
61 this.javadocStart = start;
62 this.javadocEnd = start+length-1;
63 this.firstTagPosition = this.javadocStart;
66 this.docComment.setSourceRange(start, length);
67 if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
68 setComment(start, length); // backward compatibility
70 return this.docComment;
74 * Sets the comment starting at the given position and with the given length.
76 * Note the only purpose of this method is to hide deprecated warnings.
77 * @deprecated mark deprecated to hide deprecated usage
79 private void setComment(int start, int length) {
80 this.docComment.setComment(new String(this.source, start, length));
83 public String toString() {
84 StringBuffer buffer = new StringBuffer();
85 buffer.append("javadoc: ").append(this.docComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
86 buffer.append(super.toString());
87 return buffer.toString();
91 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int)
93 protected Object createArgumentReference(char[] name, int dim, boolean isVarargs, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException {
95 MethodRefParameter argument = this.ast.newMethodRefParameter();
96 ASTNode node = (ASTNode) typeRef;
97 int argStart = node.getStartPosition();
98 int argEnd = node.getStartPosition()+node.getLength()-1;
99 if (dim > 0) argEnd = (int) dimPositions[dim-1];
100 if (argNamePos >= 0) argEnd = (int) argNamePos;
101 if (name.length != 0) {
102 final SimpleName argName = new SimpleName(this.ast);
103 argName.internalSetIdentifier(new String(name));
104 argument.setName(argName);
105 int argNameStart = (int) (argNamePos >>> 32);
106 argName.setSourceRange(argNameStart, argEnd-argNameStart+1);
109 if (node.getNodeType() == ASTNode.PRIMITIVE_TYPE) {
110 argType = (PrimitiveType) node;
112 // argType = this.ast.newArrayType(argType, dim);
113 // argType.setSourceRange(argStart, ((int) dimPositions[dim-1])-argStart+1);
116 Name argTypeName = (Name) node;
117 argType = this.ast.newSimpleType(argTypeName);
118 argType.setSourceRange(argStart, node.getLength());
120 if (dim > 0 && !isVarargs) {
121 for (int i=0; i<dim; i++) {
122 argType = this.ast.newArrayType(argType);
123 argType.setSourceRange(argStart, ((int) dimPositions[i])-argStart+1);
126 argument.setType(argType);
127 argument.setSourceRange(argStart, argEnd - argStart + 1);
130 catch (ClassCastException ex) {
131 throw new InvalidInputException();
135 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createFieldReference()
137 protected Object createFieldReference(Object receiver) throws InvalidInputException {
139 MemberRef fieldRef = this.ast.newMemberRef();
140 SimpleName fieldName = new SimpleName(this.ast);
141 fieldName.internalSetIdentifier(new String(this.identifierStack[0]));
142 fieldRef.setName(fieldName);
143 int start = (int) (this.identifierPositionStack[0] >>> 32);
144 int end = (int) this.identifierPositionStack[0];
145 fieldName.setSourceRange(start, end - start + 1);
146 if (receiver == null) {
147 start = this.memberStart;
148 fieldRef.setSourceRange(start, end - start + 1);
150 Name typeRef = (Name) receiver;
151 fieldRef.setQualifier(typeRef);
152 start = typeRef.getStartPosition();
153 end = fieldName.getStartPosition()+fieldName.getLength()-1;
154 fieldRef.setSourceRange(start, end-start+1);
158 catch (ClassCastException ex) {
159 throw new InvalidInputException();
163 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[])
165 protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException {
168 MethodRef methodRef = this.ast.newMethodRef();
169 SimpleName methodName = new SimpleName(this.ast);
170 int length = this.identifierLengthStack[0] - 1; // may be > 0 for member class constructor reference
171 methodName.internalSetIdentifier(new String(this.identifierStack[length]));
172 methodRef.setName(methodName);
173 int start = (int) (this.identifierPositionStack[length] >>> 32);
174 int end = (int) this.identifierPositionStack[length];
175 methodName.setSourceRange(start, end - start + 1);
177 if (receiver == null) {
178 start = this.memberStart;
179 methodRef.setSourceRange(start, end - start + 1);
181 Name typeRef = (Name) receiver;
182 methodRef.setQualifier(typeRef);
183 start = typeRef.getStartPosition();
186 if (arguments != null) {
187 Iterator parameters = arguments.listIterator();
188 while (parameters.hasNext()) {
189 MethodRefParameter param = (MethodRefParameter) parameters.next();
190 methodRef.parameters().add(param);
193 methodRef.setSourceRange(start, this.scanner.getCurrentTokenEndPosition()-start+1);
196 catch (ClassCastException ex) {
197 throw new InvalidInputException();
202 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTag()
204 protected void createTag() {
205 TagElement tagElement = this.ast.newTagElement();
206 int position = this.scanner.currentPosition;
207 this.scanner.resetTo(this.tagSourceStart, this.tagSourceEnd);
208 StringBuffer tagName = new StringBuffer();
209 int start = this.tagSourceStart;
210 this.scanner.getNextChar();
211 while (this.scanner.currentPosition <= (this.tagSourceEnd+1)) {
212 tagName.append(this.scanner.currentCharacter);
213 this.scanner.getNextChar();
215 tagElement.setTagName(tagName.toString());
216 if (this.inlineTagStarted) {
217 start = this.inlineTagStart;
218 TagElement previousTag = null;
219 if (this.astPtr == -1) {
220 previousTag = this.ast.newTagElement();
221 previousTag.setSourceRange(start, this.tagSourceEnd-start+1);
222 pushOnAstStack(previousTag, true);
224 previousTag = (TagElement) this.astStack[this.astPtr];
226 int previousStart = previousTag.getStartPosition();
227 previousTag.fragments().add(tagElement);
228 previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1);
230 pushOnAstStack(tagElement, true);
232 tagElement.setSourceRange(start, this.tagSourceEnd-start+1);
233 this.scanner.resetTo(position, this.javadocEnd);
237 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTypeReference()
239 protected Object createTypeReference(int primitiveToken) {
240 int size = this.identifierLengthStack[this.identifierLengthPtr];
241 String[] identifiers = new String[size];
242 int pos = this.identifierPtr - size + 1;
243 for (int i = 0; i < size; i++) {
244 identifiers[i] = new String(this.identifierStack[pos+i]);
246 ASTNode typeRef = null;
247 if (primitiveToken == -1) {
248 typeRef = this.ast.internalNewName(identifiers);
250 switch (primitiveToken) {
251 case TerminalTokens.TokenNamevoid :
252 typeRef = this.ast.newPrimitiveType(PrimitiveType.VOID);
254 case TerminalTokens.TokenNameboolean :
255 typeRef = this.ast.newPrimitiveType(PrimitiveType.BOOLEAN);
257 case TerminalTokens.TokenNamebyte :
258 typeRef = this.ast.newPrimitiveType(PrimitiveType.BYTE);
260 case TerminalTokens.TokenNamechar :
261 typeRef = this.ast.newPrimitiveType(PrimitiveType.CHAR);
263 case TerminalTokens.TokenNamedouble :
264 typeRef = this.ast.newPrimitiveType(PrimitiveType.DOUBLE);
266 case TerminalTokens.TokenNamefloat :
267 typeRef = this.ast.newPrimitiveType(PrimitiveType.FLOAT);
269 case TerminalTokens.TokenNameint :
270 typeRef = this.ast.newPrimitiveType(PrimitiveType.INT);
272 case TerminalTokens.TokenNamelong :
273 typeRef = this.ast.newPrimitiveType(PrimitiveType.LONG);
275 case TerminalTokens.TokenNameshort :
276 typeRef = this.ast.newPrimitiveType(PrimitiveType.SHORT);
283 // Update ref for whole name
284 int start = (int) (this.identifierPositionStack[pos] >>> 32);
285 // int end = (int) this.identifierPositionStack[this.identifierPtr];
286 // typeRef.setSourceRange(start, end-start+1);
287 // Update references of each simple name
289 Name name = (Name)typeRef;
290 int nameIndex = size;
291 for (int i=this.identifierPtr; i>pos; i--, nameIndex--) {
292 int s = (int) (this.identifierPositionStack[i] >>> 32);
293 int e = (int) this.identifierPositionStack[i];
294 name.index = nameIndex;
295 SimpleName simpleName = ((QualifiedName)name).getName();
296 simpleName.index = nameIndex;
297 simpleName.setSourceRange(s, e-s+1);
298 name.setSourceRange(start, e-start+1);
299 name = ((QualifiedName)name).getQualifier();
301 int end = (int) this.identifierPositionStack[pos];
302 name.setSourceRange(start, end-start+1);
303 name.index = nameIndex;
305 int end = (int) this.identifierPositionStack[pos];
306 typeRef.setSourceRange(start, end-start+1);
312 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseIdentifierTag(boolean)
314 protected boolean parseIdentifierTag(boolean report) {
315 if (super.parseIdentifierTag(report)) {
317 this.index = this.tagSourceEnd+1;
318 this.scanner.resetTo(this.index, this.javadocEnd);
325 * Parse @return tag declaration
327 protected boolean parseReturn() {
333 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTag(int)
335 protected boolean parseTag(int previousPosition) throws InvalidInputException {
338 int currentPosition = this.index;
339 int token = readTokenAndConsume();
340 char[] tagName = CharOperation.NO_CHAR;
341 if (currentPosition == this.scanner.startPosition) {
342 this.tagSourceStart = this.scanner.getCurrentTokenStartPosition();
343 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
344 tagName = this.scanner.getCurrentIdentifierSource();
346 this.tagSourceEnd = currentPosition-1;
349 // Try to get tag name other than java identifier
350 // (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51660)
351 if (this.scanner.currentCharacter != ' ' && !ScannerHelper.isWhitespace(this.scanner.currentCharacter)) {
352 tagNameToken: while (token != TerminalTokens.TokenNameEOF && this.index < this.scanner.eofPosition) {
353 int length = tagName.length;
354 // !, ", #, %, &, ', -, :, <, >, * chars and spaces are not allowed in tag names
355 switch (this.scanner.currentCharacter) {
357 case '*': // break for '*' as this is perhaps the end of comment (bug 65288)
368 case '-': // allowed in tag names as this character is often used in doclets (bug 68087)
369 System.arraycopy(tagName, 0, tagName = new char[length+1], 0, length);
370 tagName[length] = this.scanner.currentCharacter;
373 if (this.scanner.currentCharacter == ' ' || ScannerHelper.isWhitespace(this.scanner.currentCharacter)) {
376 token = readTokenAndConsume();
377 char[] ident = this.scanner.getCurrentIdentifierSource();
378 System.arraycopy(tagName, 0, tagName = new char[length+ident.length], 0, length);
379 System.arraycopy(ident, 0, tagName, length, ident.length);
382 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
383 this.scanner.getNextChar();
384 this.index = this.scanner.currentPosition;
387 int length = tagName.length;
388 this.index = this.tagSourceEnd+1;
389 this.scanner.currentPosition = this.tagSourceEnd+1;
390 this.tagSourceStart = previousPosition;
392 // tage name may be empty (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=125903)
393 if (tagName.length == 0) {
397 // Decide which parse to perform depending on tag name
398 this.tagValue = NO_TAG_VALUE;
399 boolean valid = true;
401 case TerminalTokens.TokenNameIdentifier :
402 switch (tagName[0]) {
404 if (length == TAG_CATEGORY_LENGTH && CharOperation.equals(TAG_CATEGORY, tagName)) {
405 this.tagValue = TAG_CATEGORY_VALUE;
406 valid = parseIdentifierTag(false); // TODO (frederic) reconsider parameter value when @category will be significant in spec
408 this.tagValue = TAG_OTHERS_VALUE;
413 if (length == TAG_DEPRECATED_LENGTH && CharOperation.equals(TAG_DEPRECATED, tagName)) {
414 this.deprecated = true;
415 this.tagValue = TAG_DEPRECATED_VALUE;
417 this.tagValue = TAG_OTHERS_VALUE;
422 if (length == TAG_INHERITDOC_LENGTH && CharOperation.equals(TAG_INHERITDOC, tagName)) {
423 // inhibits inherited flag when tags have been already stored
424 // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51606
425 // Note that for DOM_PARSER, nodes stack may be not empty even no '@' tag
426 // was encountered in comment. But it cannot be the case for COMPILER_PARSER
427 // and so is enough as it is only this parser which signals the missing tag warnings...
428 if (this.astPtr==-1) {
429 this.inheritedPositions = (((long) this.tagSourceStart) << 32) + this.tagSourceEnd;
431 this.tagValue = TAG_INHERITDOC_VALUE;
433 this.tagValue = TAG_OTHERS_VALUE;
438 if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
439 this.tagValue = TAG_PARAM_VALUE;
440 valid = parseParam();
442 this.tagValue = TAG_OTHERS_VALUE;
447 if (length == TAG_EXCEPTION_LENGTH && CharOperation.equals(TAG_EXCEPTION, tagName)) {
448 this.tagValue = TAG_EXCEPTION_VALUE;
449 valid = parseThrows();
451 this.tagValue = TAG_OTHERS_VALUE;
456 if (length == TAG_SEE_LENGTH && CharOperation.equals(TAG_SEE, tagName)) {
457 this.tagValue = TAG_SEE_VALUE;
458 if (this.inlineTagStarted) {
459 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
460 // Cannot have @see inside inline comment
463 valid = parseReference();
466 this.tagValue = TAG_OTHERS_VALUE;
471 if (length == TAG_LINK_LENGTH && CharOperation.equals(TAG_LINK, tagName)) {
472 this.tagValue = TAG_LINK_VALUE;
473 } else if (length == TAG_LINKPLAIN_LENGTH && CharOperation.equals(TAG_LINKPLAIN, tagName)) {
474 this.tagValue = TAG_LINKPLAIN_VALUE;
476 if (this.tagValue != NO_TAG_VALUE) {
477 if (this.inlineTagStarted) {
478 valid = parseReference();
480 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
481 // Cannot have @link outside inline comment
485 this.tagValue = TAG_OTHERS_VALUE;
490 if (this.sourceLevel >= ClassFileConstants.JDK1_5 && length == TAG_VALUE_LENGTH && CharOperation.equals(TAG_VALUE, tagName)) {
491 this.tagValue = TAG_VALUE_VALUE;
492 if (this.inlineTagStarted) {
493 valid = parseReference();
498 this.tagValue = TAG_OTHERS_VALUE;
503 this.tagValue = TAG_OTHERS_VALUE;
507 case TerminalTokens.TokenNamereturn :
508 this.tagValue = TAG_RETURN_VALUE;
509 valid = parseReturn();
511 case TerminalTokens.TokenNamethrows :
512 this.tagValue = TAG_THROWS_VALUE;
513 valid = parseThrows();
515 case TerminalTokens.TokenNameabstract:
516 case TerminalTokens.TokenNameassert:
517 case TerminalTokens.TokenNameboolean:
518 case TerminalTokens.TokenNamebreak:
519 case TerminalTokens.TokenNamebyte:
520 case TerminalTokens.TokenNamecase:
521 case TerminalTokens.TokenNamecatch:
522 case TerminalTokens.TokenNamechar:
523 case TerminalTokens.TokenNameclass:
524 case TerminalTokens.TokenNamecontinue:
525 case TerminalTokens.TokenNamedefault:
526 case TerminalTokens.TokenNamedo:
527 case TerminalTokens.TokenNamedouble:
528 case TerminalTokens.TokenNameelse:
529 case TerminalTokens.TokenNameextends:
530 case TerminalTokens.TokenNamefalse:
531 case TerminalTokens.TokenNamefinal:
532 case TerminalTokens.TokenNamefinally:
533 case TerminalTokens.TokenNamefloat:
534 case TerminalTokens.TokenNamefor:
535 case TerminalTokens.TokenNameif:
536 case TerminalTokens.TokenNameimplements:
537 case TerminalTokens.TokenNameimport:
538 case TerminalTokens.TokenNameinstanceof:
539 case TerminalTokens.TokenNameint:
540 case TerminalTokens.TokenNameinterface:
541 case TerminalTokens.TokenNamelong:
542 case TerminalTokens.TokenNamenative:
543 case TerminalTokens.TokenNamenew:
544 case TerminalTokens.TokenNamenull:
545 case TerminalTokens.TokenNamepackage:
546 case TerminalTokens.TokenNameprivate:
547 case TerminalTokens.TokenNameprotected:
548 case TerminalTokens.TokenNamepublic:
549 case TerminalTokens.TokenNameshort:
550 case TerminalTokens.TokenNamestatic:
551 case TerminalTokens.TokenNamestrictfp:
552 case TerminalTokens.TokenNamesuper:
553 case TerminalTokens.TokenNameswitch:
554 case TerminalTokens.TokenNamesynchronized:
555 case TerminalTokens.TokenNamethis:
556 case TerminalTokens.TokenNamethrow:
557 case TerminalTokens.TokenNametransient:
558 case TerminalTokens.TokenNametrue:
559 case TerminalTokens.TokenNametry:
560 case TerminalTokens.TokenNamevoid:
561 case TerminalTokens.TokenNamevolatile:
562 case TerminalTokens.TokenNamewhile:
563 this.tagValue = TAG_OTHERS_VALUE;
567 this.textStart = this.index;
572 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushParamName(java.lang.Object)
574 protected boolean pushParamName(boolean isTypeParam) {
575 int idIndex = isTypeParam ? 1 : 0;
576 final SimpleName name = new SimpleName(this.ast);
577 name.internalSetIdentifier(new String(this.identifierStack[idIndex]));
578 int nameStart = (int) (this.identifierPositionStack[idIndex] >>> 32);
579 int nameEnd = (int) (this.identifierPositionStack[idIndex] & 0x00000000FFFFFFFFL);
580 name.setSourceRange(nameStart, nameEnd-nameStart+1);
581 TagElement paramTag = this.ast.newTagElement();
582 paramTag.setTagName(TagElement.TAG_PARAM);
583 if (isTypeParam) { // specific storage for @param <E> (see bug 79809)
584 // '<' was stored in identifiers stack
585 TextElement text = this.ast.newTextElement();
586 text.setText(new String(this.identifierStack[0]));
587 int txtStart = (int) (this.identifierPositionStack[0] >>> 32);
588 int txtEnd = (int) (this.identifierPositionStack[0] & 0x00000000FFFFFFFFL);
589 text.setSourceRange(txtStart, txtEnd-txtStart+1);
590 paramTag.fragments().add(text);
592 paramTag.fragments().add(name);
593 // '>' was stored in identifiers stack
594 text = this.ast.newTextElement();
595 text.setText(new String(this.identifierStack[2]));
596 txtStart = (int) (this.identifierPositionStack[2] >>> 32);
597 txtEnd = (int) (this.identifierPositionStack[2] & 0x00000000FFFFFFFFL);
598 text.setSourceRange(txtStart, txtEnd-txtStart+1);
599 paramTag.fragments().add(text);
600 // set param tag source range
601 paramTag.setSourceRange(this.tagSourceStart, txtEnd-this.tagSourceStart+1);
603 paramTag.setSourceRange(this.tagSourceStart, nameEnd-this.tagSourceStart+1);
604 paramTag.fragments().add(name);
606 pushOnAstStack(paramTag, true);
610 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushSeeRef(java.lang.Object)
612 protected boolean pushSeeRef(Object statement) {
613 TagElement seeTag = this.ast.newTagElement();
614 ASTNode node = (ASTNode) statement;
615 seeTag.fragments().add(node);
616 int end = node.getStartPosition()+node.getLength()-1;
617 if (this.inlineTagStarted) {
618 seeTag.setSourceRange(this.inlineTagStart, end-this.inlineTagStart+1);
619 switch (this.tagValue) {
621 seeTag.setTagName(TagElement.TAG_LINK);
623 case TAG_LINKPLAIN_VALUE:
624 seeTag.setTagName(TagElement.TAG_LINKPLAIN);
626 case TAG_VALUE_VALUE:
627 seeTag.setTagName(TagElement.TAG_VALUE);
630 TagElement previousTag = null;
631 int previousStart = this.inlineTagStart;
632 if (this.astPtr == -1) {
633 previousTag = this.ast.newTagElement();
634 pushOnAstStack(previousTag, true);
636 previousTag = (TagElement) this.astStack[this.astPtr];
637 previousStart = previousTag.getStartPosition();
639 previousTag.fragments().add(seeTag);
640 previousTag.setSourceRange(previousStart, end-previousStart+1);
642 seeTag.setTagName(TagElement.TAG_SEE);
643 seeTag.setSourceRange(this.tagSourceStart, end-this.tagSourceStart+1);
644 pushOnAstStack(seeTag, true);
649 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int)
651 protected void pushText(int start, int end) {
653 // Create text element
654 TextElement text = this.ast.newTextElement();
655 text.setText(new String( this.source, start, end-start));
656 text.setSourceRange(start, end-start);
658 // Search previous tag on which to add the text element
659 TagElement previousTag = null;
660 int previousStart = start;
661 if (this.astPtr == -1) {
662 previousTag = this.ast.newTagElement();
663 previousTag.setSourceRange(start, end-start);
664 pushOnAstStack(previousTag, true);
666 previousTag = (TagElement) this.astStack[this.astPtr];
667 previousStart = previousTag.getStartPosition();
670 // If we're in a inline tag, then retrieve previous tag in its fragments
671 List fragments = previousTag.fragments();
672 if (this.inlineTagStarted) {
673 int size = fragments.size();
675 // no existing fragment => just add the element
676 TagElement inlineTag = this.ast.newTagElement();
677 fragments.add(inlineTag);
678 previousTag = inlineTag;
680 // If last fragment is a tag, then use it as previous tag
681 ASTNode lastFragment = (ASTNode) fragments.get(size-1);
682 if (lastFragment.getNodeType() == ASTNode.TAG_ELEMENT) {
683 previousTag = (TagElement) lastFragment;
684 previousStart = previousTag.getStartPosition();
690 previousTag.fragments().add(text);
691 previousTag.setSourceRange(previousStart, end-previousStart);
696 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushThrowName(java.lang.Object)
698 protected boolean pushThrowName(Object typeRef) {
699 TagElement throwsTag = this.ast.newTagElement();
700 switch (this.tagValue) {
701 case TAG_THROWS_VALUE:
702 throwsTag.setTagName(TagElement.TAG_THROWS);
704 case TAG_EXCEPTION_VALUE:
705 throwsTag.setTagName(TagElement.TAG_EXCEPTION);
708 throwsTag.setSourceRange(this.tagSourceStart, this.scanner.getCurrentTokenEndPosition()-this.tagSourceStart+1);
709 throwsTag.fragments().add(typeRef);
710 pushOnAstStack(throwsTag, true);
715 * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#refreshInlineTagPosition(int)
717 protected void refreshInlineTagPosition(int previousPosition) {
718 if (this.astPtr != -1) {
719 TagElement previousTag = (TagElement) this.astStack[this.astPtr];
720 if (this.inlineTagStarted) {
721 int previousStart = previousTag.getStartPosition();
722 previousTag.setSourceRange(previousStart, previousPosition-previousStart+1);
723 if (previousTag.fragments().size() > 0) {
724 ASTNode inlineTag = (ASTNode) previousTag.fragments().get(previousTag.fragments().size()-1);
725 if (inlineTag.getNodeType() == ASTNode.TAG_ELEMENT) {
726 int inlineStart = inlineTag.getStartPosition();
727 inlineTag.setSourceRange(inlineStart, previousPosition-inlineStart+1);
735 * Add stored tag elements to associated comment.
737 protected void updateDocComment() {
738 for (int idx = 0; idx <= this.astPtr; idx++) {
739 this.docComment.tags().add(this.astStack[idx]);