added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / parser / JavadocParser.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.parser;
12
13 import java.util.List;
14
15 import org.eclipse.jdt.core.compiler.CharOperation;
16 import org.eclipse.jdt.core.compiler.InvalidInputException;
17 import org.eclipse.jdt.internal.compiler.ast.*;
18 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
19 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
20 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
21
22 /**
23  * Parser specialized for decoding javadoc comments
24  */
25 public class JavadocParser extends AbstractCommentParser {
26
27         // Public fields
28         public Javadoc docComment;
29         
30         // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600
31         // Store param references for tag with invalid syntax
32         private int invalidParamReferencesPtr = -1;
33         private ASTNode[] invalidParamReferencesStack;
34
35         // Store current tag stack pointer
36         private int currentAstPtr= -2;
37
38         public JavadocParser(Parser sourceParser) {
39                 super(sourceParser);
40                 this.checkDocComment = this.sourceParser.options.docCommentSupport;
41                 this.jdk15 = this.sourceParser.options.sourceLevel >= ClassFileConstants.JDK1_5;
42                 this.kind = COMPIL_PARSER;
43         }
44
45         /* (non-Javadoc)
46          * Returns true if tag @deprecated is present in javadoc comment.
47          * 
48          * If javadoc checking is enabled, will also construct an Javadoc node, which will be stored into Parser.javadoc
49          * slot for being consumed later on.
50          */
51         public boolean checkDeprecation(int javadocStart, int javadocEnd) {
52
53                 try {
54                         this.source = this.sourceParser.scanner.source;
55                         this.index = javadocStart +3;
56                         this.endComment = javadocEnd - 2;
57                         if (this.checkDocComment) {
58                                 // Initialization
59                                 this.scanner.lineEnds = this.sourceParser.scanner.lineEnds;
60                                 this.scanner.linePtr = this.sourceParser.scanner.linePtr;
61                                 this.lineEnds = this.scanner.lineEnds;
62                                 this.docComment = new Javadoc(javadocStart, javadocEnd);
63                                 commentParse(javadocStart, javadocEnd);
64                         } else {
65                                 // Init javadoc if necessary
66                                 if (this.sourceParser.options.getSeverity(CompilerOptions.MissingJavadocComments) != ProblemSeverities.Ignore) {
67                                         this.docComment = new Javadoc(javadocStart, javadocEnd);
68                                 } else {
69                                         this.docComment = null;
70                                 }
71                                 
72                                 // Parse comment
73                                 int firstLineNumber = this.sourceParser.scanner.getLineNumber(javadocStart);
74                                 int lastLineNumber = this.sourceParser.scanner.getLineNumber(javadocEnd);
75         
76                                 // scan line per line, since tags must be at beginning of lines only
77                                 nextLine : for (int line = firstLineNumber; line <= lastLineNumber; line++) {
78                                         int lineStart = line == firstLineNumber
79                                                         ? javadocStart + 3 // skip leading /**
80                                                         : this.sourceParser.scanner.getLineStart(line);
81                                         this.index = lineStart;
82                                         this.lineEnd = line == lastLineNumber
83                                                         ? javadocEnd - 2 // remove trailing * /
84                                                         : this.sourceParser.scanner.getLineEnd(line);
85                                         nextCharacter : while (this.index < this.lineEnd) {
86                                                 char c = readChar(); // consider unicodes
87                                                 switch (c) {
88                                                         case '*' :
89                                                         case '\u000c' : /* FORM FEED               */
90                                                         case ' ' :                      /* SPACE                   */
91                                                         case '\t' :                     /* HORIZONTAL TABULATION   */
92                                                         case '\n' :                     /* LINE FEED   */
93                                                         case '\r' :                     /* CR */
94                                                                 // do nothing for space or '*' characters
95                                                         continue nextCharacter;
96                                                     case '@' :
97                                                         if ((readChar() == 'd') && (readChar() == 'e') &&
98                                                                                 (readChar() == 'p') && (readChar() == 'r') &&
99                                                                                 (readChar() == 'e') && (readChar() == 'c') &&
100                                                                                 (readChar() == 'a') && (readChar() == 't') &&
101                                                                                 (readChar() == 'e') && (readChar() == 'd')) {
102                                                                         // ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
103                                                                         c = readChar();
104                                                                         if (Character.isWhitespace(c) || c == '*') {
105                                                                                 return true;
106                                                                         }
107                                                         }
108                                                 }
109                                         continue nextLine;
110                                         }
111                                 }
112                                 return false;
113                         }
114                 } finally {
115                         this.source = null; // release source as soon as finished
116                 }
117                 return this.deprecated;
118         }
119
120         public String toString() {
121                 StringBuffer buffer = new StringBuffer();
122                 buffer.append("check javadoc: ").append(this.checkDocComment).append("\n");     //$NON-NLS-1$ //$NON-NLS-2$
123                 buffer.append("javadoc: ").append(this.docComment).append("\n");        //$NON-NLS-1$ //$NON-NLS-2$
124                 buffer.append(super.toString());
125                 return buffer.toString();
126         }
127
128         /* (non-Javadoc)
129          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int)
130          */
131         protected Object createArgumentReference(char[] name, int dim, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException {
132                 try {
133                         TypeReference argTypeRef = (TypeReference) typeRef;
134                         if (dim > 0) {
135                                 long pos = (((long) argTypeRef.sourceStart) << 32) + argTypeRef.sourceEnd;
136                                 if (typeRef instanceof JavadocSingleTypeReference) {
137                                         JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef;
138                                         argTypeRef = new JavadocArraySingleTypeReference(singleRef.token, dim, pos);
139                                 } else {
140                                         JavadocQualifiedTypeReference qualifRef = (JavadocQualifiedTypeReference) typeRef;
141                                         argTypeRef = new JavadocArrayQualifiedTypeReference(qualifRef, dim);
142                                 }
143                         }
144                         int argEnd = argTypeRef.sourceEnd;
145                         if (dim > 0) argEnd = (int) dimPositions[dim-1];
146                         if (argNamePos >= 0) argEnd = (int) argNamePos;
147                         return new JavadocArgumentExpression(name, argTypeRef.sourceStart, argEnd, argTypeRef);
148                 }
149                 catch (ClassCastException ex) {
150                                 throw new InvalidInputException();
151                 }
152         }
153         /* (non-Javadoc)
154          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createFieldReference()
155          */
156         protected Object createFieldReference(Object receiver) throws InvalidInputException {
157                 try {
158                         // Get receiver type
159                         TypeReference typeRef = (TypeReference) receiver;
160                         if (typeRef == null) {
161                                 char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName();
162                                 typeRef = new ImplicitDocTypeReference(name, this.memberStart);
163                         }
164                         // Create field
165                         JavadocFieldReference field = new JavadocFieldReference(this.identifierStack[0], this.identifierPositionStack[0]);
166                         field.receiver = typeRef;
167                         field.tagSourceStart = this.tagSourceStart;
168                         field.tagSourceEnd = this.tagSourceEnd;
169                         field.tagValue = this.tagValue;
170                         return field;
171                 }
172                 catch (ClassCastException ex) {
173                         throw new InvalidInputException();
174                 }
175         }
176         /* (non-Javadoc)
177          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[])
178          */
179         protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException {
180                 try {
181                         // Get receiver type
182                         TypeReference typeRef = (TypeReference) receiver;
183                         // Decide whether we have a constructor or not
184                         boolean isConstructor = false;
185                         if (typeRef == null) {
186                                 char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName();
187                                 isConstructor = CharOperation.equals(this.identifierStack[0], name);
188                                 typeRef = new ImplicitDocTypeReference(name, this.memberStart);
189                         } else {
190                                 char[] name = null;
191                                 if (typeRef instanceof JavadocSingleTypeReference) {
192                                         name = ((JavadocSingleTypeReference)typeRef).token;
193                                 } else if (typeRef instanceof JavadocQualifiedTypeReference) {
194                                         char[][] tokens = ((JavadocQualifiedTypeReference)typeRef).tokens;
195                                         name = tokens[tokens.length-1];
196                                 } else {
197                                         throw new InvalidInputException();
198                                 }
199                                 isConstructor = CharOperation.equals(this.identifierStack[0], name);
200                         }
201                         // Create node
202                         if (arguments == null) {
203                                 if (isConstructor) {
204                                         JavadocAllocationExpression alloc = new JavadocAllocationExpression(this.identifierPositionStack[0]);
205                                         alloc.type = typeRef;
206                                         alloc.tagValue = this.tagValue;
207                                         return alloc;
208                                 } else {
209                                         JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0]);
210                                         msg.receiver = typeRef;
211                                         msg.tagValue = this.tagValue;
212                                         return msg;
213                                 }
214                         } else {
215                                 JavadocArgumentExpression[] expressions = new JavadocArgumentExpression[arguments.size()];
216                                 arguments.toArray(expressions);
217                                 if (isConstructor) {
218                                         JavadocAllocationExpression alloc = new JavadocAllocationExpression(this.identifierPositionStack[0]);
219                                         alloc.arguments = expressions;
220                                         alloc.type = typeRef;
221                                         alloc.tagValue = this.tagValue;
222                                         return alloc;
223                                 } else {
224                                         JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0], expressions);
225                                         msg.receiver = typeRef;
226                                         msg.tagValue = this.tagValue;
227                                         return msg;
228                                 }
229                         }
230                 }
231                 catch (ClassCastException ex) {
232                                 throw new InvalidInputException();
233                 }
234         }
235         /* (non-Javadoc)
236          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createReturnStatement()
237          */
238         protected Object createReturnStatement() {
239                 return new JavadocReturnStatement(this.scanner.getCurrentTokenStartPosition(),
240                                         this.scanner.getCurrentTokenEndPosition(),
241                                         this.scanner.getRawTokenSourceEnd());
242         }
243         /* (non-Javadoc)
244          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTypeReference()
245          */
246         protected Object createTypeReference(int primitiveToken) {
247                 TypeReference typeRef = null;
248                 int size = this.identifierLengthStack[this.identifierLengthPtr--];
249                 if (size == 1) { // Single Type ref
250                         typeRef = new JavadocSingleTypeReference(
251                                                 this.identifierStack[this.identifierPtr],
252                                                 this.identifierPositionStack[this.identifierPtr],
253                                                 this.tagSourceStart,
254                                                 this.tagSourceEnd);
255                 } else if (size > 1) { // Qualified Type ref
256                         char[][] tokens = new char[size][];
257                         System.arraycopy(this.identifierStack, this.identifierPtr - size + 1, tokens, 0, size);
258                         long[] positions = new long[size];
259                         System.arraycopy(this.identifierPositionStack, this.identifierPtr - size + 1, positions, 0, size);
260                         typeRef = new JavadocQualifiedTypeReference(tokens, positions, this.tagSourceStart, this.tagSourceEnd);
261                 }
262                 this.identifierPtr -= size;
263                 return typeRef;
264         }
265
266         /*
267          * Parse @return tag declaration
268          */
269         protected boolean parseReturn() {
270                 if (this.returnStatement == null) {
271                         this.returnStatement = createReturnStatement();
272                         this.currentAstPtr = this.astPtr;
273                         return true;
274                 }
275                 if (this.sourceParser != null) this.sourceParser.problemReporter().javadocDuplicatedReturnTag(
276                                 this.scanner.getCurrentTokenStartPosition(),
277                                 this.scanner.getCurrentTokenEndPosition());
278                 return false;
279         }
280
281         /* (non-Javadoc)
282          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTag(int)
283          */
284         protected boolean parseTag(int previousPosition) throws InvalidInputException {
285                 boolean valid = false;
286
287                 // In case of previous return tag, set it to not empty if parsing an inline tag
288                 if (this.currentAstPtr != -2 && this.returnStatement != null) {
289                         this.currentAstPtr = -2;
290                         JavadocReturnStatement javadocReturn = (JavadocReturnStatement) this.returnStatement;
291                         javadocReturn.empty = javadocReturn.empty && !this.inlineTagStarted;
292                 }
293
294                 // Read tag name
295                 int token = readTokenAndConsume();
296                 this.tagSourceStart = this.scanner.getCurrentTokenStartPosition();
297                 this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition();
298                 char[] tag = this.scanner.getCurrentIdentifierSource(); // first token is either an identifier or a keyword
299
300                 // Decide which parse to perform depending on tag name
301                 this.tagValue = NO_TAG_VALUE;
302                 switch (token) {
303                         case TerminalTokens.TokenNameIdentifier :
304                                 switch (tag[0]) {
305                                         case 'd':
306                                                 if (CharOperation.equals(tag, TAG_DEPRECATED)) {
307                                                         this.deprecated = true;
308                                                         valid = true;
309                                                         this.tagValue = TAG_DEPRECATED_VALUE;
310                                                 }
311                                         break;
312                                         case 'i':
313                                                 if (CharOperation.equals(tag, TAG_INHERITDOC)) {
314                                                         // inhibits inherited flag when tags have been already stored
315                                                         // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51606
316                                                         // Note that for DOM_PARSER, nodes stack may be not empty even no '@' tag
317                                                         // was encountered in comment. But it cannot be the case for COMPILER_PARSER
318                                                         // and so is enough as it is only this parser which signals the missing tag warnings...
319                                                         this.inherited = this.astPtr==-1;
320                                                         valid = true;
321                                                         this.tagValue = TAG_INHERITDOC_VALUE;
322                                                 }
323                                         break;
324                                         case 'p':
325                                                 if (CharOperation.equals(tag, TAG_PARAM)) {
326                                                         this.tagValue = TAG_PARAM_VALUE;
327                                                         valid = parseParam();
328                                                 }
329                                         break;
330                                         case 'e':
331                                                 if (CharOperation.equals(tag, TAG_EXCEPTION)) {
332                                                         this.tagValue = TAG_EXCEPTION_VALUE;
333                                                         valid = parseThrows();
334                                                 }
335                                         break;
336                                         case 's':
337                                                 if (CharOperation.equals(tag, TAG_SEE)) {
338                                                         if (this.inlineTagStarted) {
339                                                                 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
340                                                                 // Cannot have @see inside inline comment
341                                                                 valid = false;
342                                                                 if (this.sourceParser != null)
343                                                                         this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd);
344                                                         } else {
345                                                                 this.tagValue = TAG_SEE_VALUE;
346                                                                 valid = parseReference();
347                                                         }
348                                                 }
349                                         break;
350                                         case 'l':
351                                                 if (CharOperation.equals(tag, TAG_LINK)) {
352                                                         this.tagValue = TAG_LINK_VALUE;
353                                                         if (this.inlineTagStarted) {
354                                                                 valid= parseReference();
355                                                         } else {
356                                                                 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290
357                                                                 // Cannot have @link outside inline comment
358                                                                 valid = false;
359                                                                 if (this.sourceParser != null)
360                                                                         this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd);
361                                                         }
362                                                 } else if (CharOperation.equals(tag, TAG_LINKPLAIN)) {
363                                                         this.tagValue = TAG_LINKPLAIN_VALUE;
364                                                         if (this.inlineTagStarted) {
365                                                                 valid = parseReference();
366                                                         } else {
367                                                                 valid = false;
368                                                                 if (this.sourceParser != null)
369                                                                         this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd);
370                                                         }
371                                                 }
372                                         break;
373                                         case 'v':
374                                                 if (this.jdk15 && CharOperation.equals(tag, TAG_VALUE)) {
375                                                         this.tagValue = TAG_VALUE_VALUE;
376                                                         if (this.inlineTagStarted) {
377                                                                 valid = parseReference();
378                                                         } else {
379                                                                 valid = false;
380                                                                 if (this.sourceParser != null)
381                                                                         this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd);
382                                                         }
383                                                 } else {
384                                                         createTag();
385                                                 }
386                                         break;
387                                 }
388                                 break;
389                         case TerminalTokens.TokenNamereturn :
390                                 this.tagValue = TAG_RETURN_VALUE;
391                                 valid = parseReturn();
392                                 /* verify characters after return tag (we're expecting text description)
393                                 if(!verifyCharsAfterReturnTag(this.index)) {
394                                         if (this.sourceParser != null) {
395                                                 int end = this.starPosition == -1 || this.lineEnd<this.starPosition ? this.lineEnd : this.starPosition;
396                                                 this.sourceParser.problemReporter().javadocEmptyReturnTag(this.tagSourceStart, end);
397                                         }
398                                 }
399                                 */
400                                 break;
401                         case TerminalTokens.TokenNamethrows :
402                                 this.tagValue = TAG_THROWS_VALUE;
403                                 valid = parseThrows();
404                                 break;
405                 }
406                 this.textStart = this.index;
407                 return valid;
408         }
409
410         /* (non-Javadoc)
411          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTagName()
412          */
413         protected void createTag() {
414                 this.tagValue = TAG_OTHERS_VALUE;
415         }
416
417         /*
418          * Push a param name in ast node stack.
419          */
420         protected boolean pushParamName(boolean isTypeParam) {
421                 // Create param reference
422                 ASTNode nameRef = null;
423                 if (isTypeParam) {
424                         JavadocSingleTypeReference ref = new JavadocSingleTypeReference(this.identifierStack[1],
425                                 this.identifierPositionStack[1],
426                                 this.tagSourceStart,
427                                 this.tagSourceEnd);
428                         nameRef = ref;
429                 } else {
430                         JavadocSingleNameReference ref = new JavadocSingleNameReference(this.identifierStack[0],
431                                 this.identifierPositionStack[0],
432                                 this.tagSourceStart,
433                                 this.tagSourceEnd);
434                         nameRef = ref;
435                 }
436                 // Push ref on stack
437                 if (this.astLengthPtr == -1) { // First push
438                         pushOnAstStack(nameRef, true);
439                 } else {
440                         // Verify that no @throws has been declared before
441                         if (!isTypeParam) { // do not verify for type parameters as @throws may be invalid tag (when declared in class)
442                                 for (int i=THROWS_TAG_EXPECTED_ORDER; i<=this.astLengthPtr; i+=ORDERED_TAGS_NUMBER) {
443                                         if (this.astLengthStack[i] != 0) {
444                                                 if (this.sourceParser != null) this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd);
445                                                 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600
446                                                 // store invalid param references in specific array
447                                                 if (this.invalidParamReferencesPtr == -1l) {
448                                                         this.invalidParamReferencesStack = new JavadocSingleNameReference[10];
449                                                 }
450                                                 int stackLength = this.invalidParamReferencesStack.length;
451                                                 if (++this.invalidParamReferencesPtr >= stackLength) {
452                                                         System.arraycopy(
453                                                                 this.invalidParamReferencesStack, 0,
454                                                                 this.invalidParamReferencesStack = new JavadocSingleNameReference[stackLength + AstStackIncrement], 0,
455                                                                 stackLength);
456                                                 }
457                                                 this.invalidParamReferencesStack[this.invalidParamReferencesPtr] = nameRef;
458                                                 return false;
459                                         }
460                                 }
461                         }
462                         switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) {
463                                 case PARAM_TAG_EXPECTED_ORDER :
464                                         // previous push was a @param tag => push another param name
465                                         pushOnAstStack(nameRef, false);
466                                         break;
467                                 case SEE_TAG_EXPECTED_ORDER :
468                                         // previous push was a @see tag => push new param name
469                                         pushOnAstStack(nameRef, true);
470                                         break;
471                                 default:
472                                         return false;
473                         }
474                 }
475                 return true;
476         }
477
478         /*
479          * Push a reference statement in ast node stack.
480          */
481         protected boolean pushSeeRef(Object statement) {
482                 if (this.astLengthPtr == -1) { // First push
483                         pushOnAstStack(null, true);
484                         pushOnAstStack(null, true);
485                         pushOnAstStack(statement, true);
486                 } else {
487                         switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) {
488                                 case PARAM_TAG_EXPECTED_ORDER :
489                                         // previous push was a @param tag => push empty @throws tag and new @see tag
490                                         pushOnAstStack(null, true);
491                                         pushOnAstStack(statement, true);
492                                         break;
493                                 case THROWS_TAG_EXPECTED_ORDER :
494                                         // previous push was a @throws tag => push new @see tag
495                                         pushOnAstStack(statement, true);
496                                         break;
497                                 case SEE_TAG_EXPECTED_ORDER :
498                                         // previous push was a @see tag => push another @see tag
499                                         pushOnAstStack(statement, false);
500                                         break;
501                                 default:
502                                         return false;
503                         }
504                 }
505                 return true;
506         }
507
508         /* (non-Javadoc)
509          * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int)
510          */
511         protected void pushText(int start, int end) {
512                 // In case of previous return tag, verify that text make it not empty
513                 if (this.currentAstPtr != -2 && this.returnStatement != null) {
514                         int position = this.index;
515                         this.index = start;
516                         boolean empty = true;
517                         boolean star = false;
518                         char ch = readChar();
519                         // Look for first character other than white or '*'
520                         if (Character.isWhitespace(ch) || start>(this.tagSourceEnd+1)) {
521                                 while (this.index <= end && empty) {
522                                         if (!star) {
523                                                 empty = Character.isWhitespace(ch) || ch == '*';
524                                                 star = ch == '*';
525                                         } else if (ch != '*') {
526                                                 empty = false;
527                                                 break;
528                                         }
529                                         ch = readChar();
530                                 }
531                         }
532                         // Store result in previous return tag
533                         ((JavadocReturnStatement)this.returnStatement).empty = empty;
534                         // Reset position and current ast ptr if we are on a different tag than previous return one
535                         this.index = position;
536                         if (this.currentAstPtr != this.astPtr) {
537                                 this.currentAstPtr = -2;
538                         }
539                 }
540         }
541
542         /*
543          * Push a throws type ref in ast node stack.
544          */
545         protected boolean pushThrowName(Object typeRef) {
546                 if (this.astLengthPtr == -1) { // First push
547                         pushOnAstStack(null, true);
548                         pushOnAstStack(typeRef, true);
549                 } else {
550                         switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) {
551                                 case PARAM_TAG_EXPECTED_ORDER :
552                                         // previous push was a @param tag => push new @throws tag
553                                         pushOnAstStack(typeRef, true);
554                                         break;
555                                 case THROWS_TAG_EXPECTED_ORDER :
556                                         // previous push was a @throws tag => push another @throws tag
557                                         pushOnAstStack(typeRef, false);
558                                         break;
559                                 case SEE_TAG_EXPECTED_ORDER :
560                                         // previous push was a @see tag => push empty @param and new @throws tags
561                                         pushOnAstStack(null, true);
562                                         pushOnAstStack(typeRef, true);
563                                         break;
564                                 default:
565                                         return false;
566                         }
567                 }
568                 return true;
569         }
570
571         /*
572          * Fill associated comment fields with ast nodes information stored in stack.
573          */
574         protected void updateDocComment() {
575                 
576                 // Set inherited flag
577                 this.docComment.inherited = this.inherited;
578
579                 // Set return node if present
580                 if (this.returnStatement != null) {
581                         this.docComment.returnStatement = (JavadocReturnStatement) this.returnStatement;
582                 }
583                 
584                 // Copy array of invalid syntax param tags
585                 if (this.invalidParamReferencesPtr >= 0) {
586                         this.docComment.invalidParameters = new JavadocSingleNameReference[this.invalidParamReferencesPtr+1];
587                         System.arraycopy(this.invalidParamReferencesStack, 0, this.docComment.invalidParameters, 0, this.invalidParamReferencesPtr+1);
588                 }
589
590                 // If no nodes stored return
591                 if (this.astLengthPtr == -1) {
592                         return;
593                 }
594
595                 // Initialize arrays
596                 int[] sizes = new int[ORDERED_TAGS_NUMBER];
597                 for (int i=0; i<=this.astLengthPtr; i++) {
598                         sizes[i%ORDERED_TAGS_NUMBER] += this.astLengthStack[i];
599                 }
600                 this.docComment.seeReferences = new Expression[sizes[SEE_TAG_EXPECTED_ORDER]];
601                 this.docComment.exceptionReferences = new TypeReference[sizes[THROWS_TAG_EXPECTED_ORDER]];
602                 this.docComment.paramReferences = new JavadocSingleNameReference[sizes[PARAM_TAG_EXPECTED_ORDER]];
603                 int paramRefPtr = sizes[PARAM_TAG_EXPECTED_ORDER];
604                 this.docComment.paramTypeParameters = new JavadocSingleTypeReference[sizes[PARAM_TAG_EXPECTED_ORDER]];
605                 int paramTypeParamPtr = sizes[PARAM_TAG_EXPECTED_ORDER];
606
607                 // Store nodes in arrays
608                 while (this.astLengthPtr >= 0) {
609                         int ptr = this.astLengthPtr % ORDERED_TAGS_NUMBER;
610                         // Starting with the stack top, so get references (eg. Expression) coming from @see declarations
611                         switch(ptr) {
612                                 case SEE_TAG_EXPECTED_ORDER:
613                                         int size = this.astLengthStack[this.astLengthPtr--];
614                                         for (int i=0; i<size; i++) {
615                                                 this.docComment.seeReferences[--sizes[ptr]] = (Expression) this.astStack[this.astPtr--];
616                                         }
617                                         break;
618
619                                 // Then continuing with class names (eg. TypeReference) coming from @throw/@exception declarations
620                                 case THROWS_TAG_EXPECTED_ORDER:
621                                         size = this.astLengthStack[this.astLengthPtr--];
622                                         for (int i=0; i<size; i++) {
623                                                 this.docComment.exceptionReferences[--sizes[ptr]] = (TypeReference) this.astStack[this.astPtr--];
624                                         }
625                                         break;
626
627                                 // Finally, finishing with parameters nales (ie. Argument) coming from @param declaration
628                                 case PARAM_TAG_EXPECTED_ORDER:
629                                         size = this.astLengthStack[this.astLengthPtr--];
630                                         for (int i=0; i<size; i++) {
631                                                 Expression reference = (Expression) this.astStack[this.astPtr--];
632                                                 if (reference instanceof JavadocSingleNameReference)
633                                                         this.docComment.paramReferences[--paramRefPtr] = (JavadocSingleNameReference) reference;
634                                                 else if (reference instanceof JavadocSingleTypeReference)
635                                                         this.docComment.paramTypeParameters[--paramTypeParamPtr] = (JavadocSingleTypeReference) reference;
636                                         }
637                                         break;
638                         }
639                 }
640                 
641                 // Resize param tag references arrays
642                 if (paramRefPtr == 0) { // there's no type parameters references
643                         this.docComment.paramTypeParameters = null;
644                 } else if (paramTypeParamPtr == 0) { // there's no names references
645                         this.docComment.paramReferences = null;
646                 } else { // there both of references => resize arrays
647                         int size = sizes[PARAM_TAG_EXPECTED_ORDER];
648                         System.arraycopy(this.docComment.paramReferences, paramRefPtr, this.docComment.paramReferences = new JavadocSingleNameReference[size - paramRefPtr], 0, size - paramRefPtr);
649                         System.arraycopy(this.docComment.paramTypeParameters, paramTypeParamPtr, this.docComment.paramTypeParameters = new JavadocSingleTypeReference[size - paramTypeParamPtr], 0, size - paramTypeParamPtr);
650                 }
651         }
652 }