removed unused private methods.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / DocCommentParser.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
12
13 import java.util.Iterator;
14 import java.util.List;
15
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;
23
24 /**
25  * Internal parser used for decoding doc comments.
26  * 
27  * @since 3.0
28  */
29 class DocCommentParser extends AbstractCommentParser {
30
31         private Javadoc docComment;
32         private AST ast;
33
34         DocCommentParser(AST ast, Scanner scanner, boolean check) {
35                 super(null);
36                 this.ast = ast;
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;
41         }
42
43         /* (non-Javadoc)
44          * Returns true if tag @deprecated is present in annotation.
45          * 
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.
48          */
49         public Javadoc parse(int[] positions) {
50                 return parse(positions[0], positions[1]-positions[0]);
51         }
52         public Javadoc parse(int start, int length) {
53
54                 // Init
55                 this.source = this.scanner.source;
56                 this.lineEnds = this.scanner.lineEnds;
57                 this.docComment = new Javadoc(this.ast);
58                 
59                 // Parse
60                 if (this.checkDocComment) {
61                         this.javadocStart = start;
62                         this.javadocEnd = start+length-1;
63                         this.firstTagPosition = this.javadocStart;
64                         commentParse();
65                 }
66                 this.docComment.setSourceRange(start, length);
67                 if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
68                         setComment(start, length);  // backward compatibility
69                 }
70                 return this.docComment;
71         }
72
73         /**
74          * Sets the comment starting at the given position and with the given length.
75          * <p>
76          * Note the only purpose of this method is to hide deprecated warnings.
77          * @deprecated mark deprecated to hide deprecated usage
78          */
79         private void setComment(int start, int length) {
80                 this.docComment.setComment(new String(this.source, start, length));
81         }
82
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();
88         }
89
90         /* (non-Javadoc)
91          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int)
92          */
93         protected Object createArgumentReference(char[] name, int dim, boolean isVarargs, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException {
94                 try {
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);
107                         }
108                         Type argType = null;
109                         if (node.getNodeType() == ASTNode.PRIMITIVE_TYPE) {
110                                 argType = (PrimitiveType) node;
111 //                              if (dim > 0) {
112 //                                      argType = this.ast.newArrayType(argType, dim);
113 //                                      argType.setSourceRange(argStart, ((int) dimPositions[dim-1])-argStart+1);
114 //                              }
115                         } else {
116                                 Name argTypeName = (Name) node;
117                                 argType = this.ast.newSimpleType(argTypeName);
118                                 argType.setSourceRange(argStart, node.getLength());
119                         }
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);
124                                 }
125                         }
126                         argument.setType(argType);
127                         argument.setSourceRange(argStart, argEnd - argStart + 1);
128                         return argument;
129                 }
130                 catch (ClassCastException ex) {
131                                 throw new InvalidInputException();
132                 }
133         }
134 /* (non-Javadoc)
135          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createFieldReference()
136          */
137         protected Object createFieldReference(Object receiver) throws InvalidInputException {
138                 try {
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);
149                         } else {
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);
155                         }
156                         return fieldRef;
157                 }
158                 catch (ClassCastException ex) {
159                                 throw new InvalidInputException();
160                 }
161         }
162         /* (non-Javadoc)
163          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[])
164          */
165         protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException {
166                 try {
167                         // Create method ref
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);
176                         // Set qualifier
177                         if (receiver == null) {
178                                 start = this.memberStart;
179                                 methodRef.setSourceRange(start, end - start + 1);
180                         } else {
181                                 Name typeRef = (Name) receiver;
182                                 methodRef.setQualifier(typeRef);
183                                 start = typeRef.getStartPosition();
184                         }
185                         // Add arguments
186                         if (arguments != null) {
187                                 Iterator parameters = arguments.listIterator();
188                                 while (parameters.hasNext()) {
189                                         MethodRefParameter param = (MethodRefParameter) parameters.next();
190                                         methodRef.parameters().add(param);
191                                 }
192                         }
193                         methodRef.setSourceRange(start, this.scanner.getCurrentTokenEndPosition()-start+1);
194                         return methodRef;
195                 }
196                 catch (ClassCastException ex) {
197                                 throw new InvalidInputException();
198                 }
199         }
200
201         /* (non-Javadoc)
202          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTag()
203          */
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();
214                 }
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);
223                         } else {
224                                 previousTag = (TagElement) this.astStack[this.astPtr];
225                         }
226                         int previousStart = previousTag.getStartPosition();
227                         previousTag.fragments().add(tagElement);
228                         previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1);
229                 } else {
230                         pushOnAstStack(tagElement, true);
231                 }
232                 tagElement.setSourceRange(start, this.tagSourceEnd-start+1);
233                 this.scanner.resetTo(position, this.javadocEnd);
234         }
235
236         /* (non-Javadoc)
237          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTypeReference()
238          */
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]);
245                 }
246                 ASTNode typeRef = null;
247                 if (primitiveToken == -1) {
248                         typeRef = this.ast.internalNewName(identifiers);
249                 } else {
250                         switch (primitiveToken) {
251                                 case TerminalTokens.TokenNamevoid :
252                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.VOID);
253                                         break;
254                                 case TerminalTokens.TokenNameboolean :
255                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.BOOLEAN);
256                                         break;
257                                 case TerminalTokens.TokenNamebyte :
258                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.BYTE);
259                                         break;
260                                 case TerminalTokens.TokenNamechar :
261                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.CHAR);
262                                         break;
263                                 case TerminalTokens.TokenNamedouble :
264                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.DOUBLE);
265                                         break;
266                                 case TerminalTokens.TokenNamefloat :
267                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.FLOAT);
268                                         break;
269                                 case TerminalTokens.TokenNameint :
270                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.INT);
271                                         break;
272                                 case TerminalTokens.TokenNamelong :
273                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.LONG);
274                                         break;
275                                 case TerminalTokens.TokenNameshort :
276                                         typeRef = this.ast.newPrimitiveType(PrimitiveType.SHORT);
277                                         break;
278                                 default:
279                                         // should not happen
280                                         return null;
281                         }
282                 }
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
288                 if (size > 1) {
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();
300                         }
301                         int end = (int) this.identifierPositionStack[pos];
302                         name.setSourceRange(start, end-start+1);
303                         name.index = nameIndex;
304                 } else {
305                         int end = (int) this.identifierPositionStack[pos];
306                         typeRef.setSourceRange(start, end-start+1);
307                 }
308                 return typeRef;
309         }
310
311         /* (non-Javadoc)
312          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseIdentifierTag(boolean)
313          */
314         protected boolean parseIdentifierTag(boolean report) {
315                 if (super.parseIdentifierTag(report)) {
316                         createTag();
317                         this.index = this.tagSourceEnd+1;
318                         this.scanner.resetTo(this.index, this.javadocEnd);
319                         return true;
320                 }
321                 return false;
322         }
323
324         /*
325          * Parse @return tag declaration
326          */
327         protected boolean parseReturn() {
328                 createTag();
329                 return true;
330         }
331
332         /* (non-Javadoc)
333          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTag(int)
334          */
335         protected boolean parseTag(int previousPosition) throws InvalidInputException {
336                 
337                 // Read tag name
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();
345                 } else {
346                         this.tagSourceEnd = currentPosition-1;
347                 }
348
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) {
356                                         case '}':
357                                         case '*': // break for '*' as this is perhaps the end of comment (bug 65288)
358                                         case '!':
359                                         case '#':
360                                         case '%':
361                                         case '&':
362                                         case '\'':
363                                         case '"':
364                                         case ':':
365                                         case '<':
366                                         case '>':
367                                                 break tagNameToken;
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;
371                                                 break;
372                                         default:
373                                                 if (this.scanner.currentCharacter == ' ' || ScannerHelper.isWhitespace(this.scanner.currentCharacter)) {
374                                                         break tagNameToken;
375                                                 }
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);
380                                                 break;
381                                 }
382                                 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
383                                 this.scanner.getNextChar();
384                                 this.index = this.scanner.currentPosition;
385                         }
386                 }
387                 int length = tagName.length;
388                 this.index = this.tagSourceEnd+1;
389                 this.scanner.currentPosition = this.tagSourceEnd+1;
390                 this.tagSourceStart = previousPosition;
391
392                 // tage name may be empty (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=125903)
393                 if (tagName.length == 0) {
394                         return false;
395                 }
396
397                 // Decide which parse to perform depending on tag name
398                 this.tagValue = NO_TAG_VALUE;
399                 boolean valid = true;
400                 switch (token) {
401                         case TerminalTokens.TokenNameIdentifier :
402                                 switch (tagName[0]) {
403                                         case 'c':
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
407                                                 } else {
408                                                         this.tagValue = TAG_OTHERS_VALUE;
409                                                         createTag();
410                                                 }
411                                                 break;
412                                         case 'd':
413                                                 if (length == TAG_DEPRECATED_LENGTH && CharOperation.equals(TAG_DEPRECATED, tagName)) {
414                                                         this.deprecated = true;
415                                                         this.tagValue = TAG_DEPRECATED_VALUE;
416                                                 } else {
417                                                         this.tagValue = TAG_OTHERS_VALUE;
418                                                 }
419                                                 createTag();
420                                         break;
421                                         case 'i':
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;
430                                                         }
431                                                         this.tagValue = TAG_INHERITDOC_VALUE;
432                                                 } else {
433                                                         this.tagValue = TAG_OTHERS_VALUE;
434                                                 }
435                                                 createTag();
436                                         break;
437                                         case 'p':
438                                                 if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
439                                                         this.tagValue = TAG_PARAM_VALUE;
440                                                         valid = parseParam();
441                                                 } else {
442                                                         this.tagValue = TAG_OTHERS_VALUE;
443                                                         createTag();
444                                                 }
445                                         break;
446                                         case 'e':
447                                                 if (length == TAG_EXCEPTION_LENGTH && CharOperation.equals(TAG_EXCEPTION, tagName)) {
448                                                         this.tagValue = TAG_EXCEPTION_VALUE;
449                                                         valid = parseThrows();
450                                                 } else {
451                                                         this.tagValue = TAG_OTHERS_VALUE;
452                                                         createTag();
453                                                 }
454                                         break;
455                                         case 's':
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
461                                                                 valid = false;
462                                                         } else {
463                                                                 valid = parseReference();
464                                                         }
465                                                 } else {
466                                                         this.tagValue = TAG_OTHERS_VALUE;
467                                                         createTag();
468                                                 }
469                                         break;
470                                         case 'l':
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;
475                                                 }
476                                                 if (this.tagValue != NO_TAG_VALUE)  {
477                                                         if (this.inlineTagStarted) {
478                                                                 valid = parseReference();
479                                                         } else {
480                                                                 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
481                                                                 // Cannot have @link outside inline comment
482                                                                 valid = false;
483                                                         }
484                                                 } else {
485                                                         this.tagValue = TAG_OTHERS_VALUE;
486                                                         createTag();
487                                                 }
488                                         break;
489                                         case 'v':
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();
494                                                         } else {
495                                                                 valid = false;
496                                                         }
497                                                 } else {
498                                                         this.tagValue = TAG_OTHERS_VALUE;
499                                                         createTag();
500                                                 }
501                                         break;
502                                         default:
503                                                 this.tagValue = TAG_OTHERS_VALUE;
504                                                 createTag();
505                                 }
506                                 break;
507                         case TerminalTokens.TokenNamereturn :
508                                 this.tagValue = TAG_RETURN_VALUE;
509                                 valid = parseReturn();
510                                 break;
511                         case TerminalTokens.TokenNamethrows :
512                                 this.tagValue = TAG_THROWS_VALUE;
513                                 valid = parseThrows();
514                                 break;
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;
564                                 createTag();
565                                 break;
566                 }
567                 this.textStart = this.index;
568                 return valid;
569         }
570
571         /* (non-Javadoc)
572          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushParamName(java.lang.Object)
573          */
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);
591                         // add simple name
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);
602                 } else {
603                         paramTag.setSourceRange(this.tagSourceStart, nameEnd-this.tagSourceStart+1);
604                         paramTag.fragments().add(name);
605                 }
606                 pushOnAstStack(paramTag, true);
607                 return true;
608         }
609         /* (non-Javadoc)
610          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushSeeRef(java.lang.Object)
611          */
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) {
620                                 case TAG_LINK_VALUE:
621                                         seeTag.setTagName(TagElement.TAG_LINK);
622                                 break;
623                                 case TAG_LINKPLAIN_VALUE:
624                                         seeTag.setTagName(TagElement.TAG_LINKPLAIN);
625                                 break;
626                                 case TAG_VALUE_VALUE:
627                                         seeTag.setTagName(TagElement.TAG_VALUE);
628                                 break;
629                         }
630                         TagElement previousTag = null;
631                         int previousStart = this.inlineTagStart;
632                         if (this.astPtr == -1) {
633                                 previousTag = this.ast.newTagElement();
634                                 pushOnAstStack(previousTag, true);
635                         } else {
636                                 previousTag = (TagElement) this.astStack[this.astPtr];
637                                 previousStart = previousTag.getStartPosition();
638                         }
639                         previousTag.fragments().add(seeTag);
640                         previousTag.setSourceRange(previousStart, end-previousStart+1);
641                 } else {
642                         seeTag.setTagName(TagElement.TAG_SEE);
643                         seeTag.setSourceRange(this.tagSourceStart, end-this.tagSourceStart+1);
644                         pushOnAstStack(seeTag, true);
645                 }
646                 return true;
647         }
648         /* (non-Javadoc)
649          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int)
650          */
651         protected void pushText(int start, int end) {
652
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);
657
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);
665                 } else {
666                         previousTag = (TagElement) this.astStack[this.astPtr];
667                         previousStart = previousTag.getStartPosition();
668                 }
669
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();
674                         if (size == 0) {
675                                 // no existing fragment => just add the element
676                                 TagElement inlineTag = this.ast.newTagElement();
677                                 fragments.add(inlineTag);
678                                 previousTag = inlineTag;
679                         } else {
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();
685                                 }
686                         }
687                 }
688
689                 // Add the text
690                 previousTag.fragments().add(text);
691                 previousTag.setSourceRange(previousStart, end-previousStart);
692                 this.textStart = -1;
693         }
694
695         /* (non-Javadoc)
696          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushThrowName(java.lang.Object)
697          */
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);
703                         break;
704                         case TAG_EXCEPTION_VALUE:
705                                 throwsTag.setTagName(TagElement.TAG_EXCEPTION);
706                         break;
707                 }
708                 throwsTag.setSourceRange(this.tagSourceStart, this.scanner.getCurrentTokenEndPosition()-this.tagSourceStart+1);
709                 throwsTag.fragments().add(typeRef);
710                 pushOnAstStack(throwsTag, true);
711                 return true;
712         }
713
714         /* (non-Javadoc)
715          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#refreshInlineTagPosition(int)
716          */
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);
728                                         }
729                                 }
730                         }
731                 }
732         }
733
734         /*
735          * Add stored tag elements to associated comment.
736          */
737         protected void updateDocComment() {
738                 for (int idx = 0; idx <= this.astPtr; idx++) {
739                         this.docComment.tags().add(this.astStack[idx]);
740                 }
741         }
742 }