/******************************************************************************* | |
* Copyright (c) 2000, 2004 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.wst.jsdt.internal.compiler.parser; | |
import java.util.List; | |
import org.eclipse.wst.jsdt.core.compiler.CharOperation; | |
import org.eclipse.wst.jsdt.core.compiler.InvalidInputException; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Expression; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.ImplicitDocTypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Javadoc; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocAllocationExpression; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocArgumentExpression; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocArrayQualifiedTypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocArraySingleTypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocFieldReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocMessageSend; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocQualifiedTypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocReturnStatement; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocSingleNameReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.JavadocSingleTypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeReference; | |
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; | |
import org.eclipse.wst.jsdt.internal.compiler.impl.CompilerOptions; | |
import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemSeverities; | |
/** | |
* Parser specialized for decoding javadoc comments | |
*/ | |
public class JavadocParser extends AbstractCommentParser { | |
// Public fields | |
public Javadoc docComment; | |
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 | |
// Store param references for tag with invalid syntax | |
private int invalidParamReferencesPtr = -1; | |
private JavadocSingleNameReference[] invalidParamReferencesStack; | |
// Store current tag stack pointer | |
private int currentAstPtr= -2; | |
public JavadocParser(Parser sourceParser) { | |
super(sourceParser); | |
this.checkDocComment = this.sourceParser.options.docCommentSupport; | |
this.kind = COMPIL_PARSER; | |
} | |
/* (non-Javadoc) | |
* Returns true if tag @deprecated is present in javadoc comment. | |
* | |
* If javadoc checking is enabled, will also construct an Javadoc node, which will be stored into Parser.javadoc | |
* slot for being consumed later on. | |
*/ | |
public boolean checkDeprecation(int javadocStart, int javadocEnd) { | |
try { | |
this.source = this.sourceParser.scanner.source; | |
this.index = javadocStart +3; | |
this.endComment = javadocEnd - 2; | |
if (this.checkDocComment) { | |
// Initialization | |
this.scanner.lineEnds = this.sourceParser.scanner.lineEnds; | |
this.scanner.linePtr = this.sourceParser.scanner.linePtr; | |
this.lineEnds = this.scanner.lineEnds; | |
this.docComment = new Javadoc(javadocStart, javadocEnd); | |
commentParse(javadocStart, javadocEnd); | |
} else { | |
// Init javadoc if necessary | |
if (this.sourceParser.options.getSeverity(CompilerOptions.MissingJavadocComments) != ProblemSeverities.Ignore) { | |
this.docComment = new Javadoc(javadocStart, javadocEnd); | |
} else { | |
this.docComment = null; | |
} | |
// Parse comment | |
int firstLineNumber = this.sourceParser.scanner.getLineNumber(javadocStart); | |
int lastLineNumber = this.sourceParser.scanner.getLineNumber(javadocEnd); | |
// scan line per line, since tags must be at beginning of lines only | |
nextLine : for (int line = firstLineNumber; line <= lastLineNumber; line++) { | |
int lineStart = line == firstLineNumber | |
? javadocStart + 3 // skip leading /** | |
: this.sourceParser.scanner.getLineStart(line); | |
this.index = lineStart; | |
this.lineEnd = line == lastLineNumber | |
? javadocEnd - 2 // remove trailing * / | |
: this.sourceParser.scanner.getLineEnd(line); | |
nextCharacter : while (this.index < this.lineEnd) { | |
char c = readChar(); // consider unicodes | |
switch (c) { | |
default : | |
if (Character.isWhitespace(c)) { | |
continue nextCharacter; | |
} | |
break; | |
case '*' : | |
continue nextCharacter; | |
case '@' : | |
if ((readChar() == 'd') && (readChar() == 'e') && | |
(readChar() == 'p') && (readChar() == 'r') && | |
(readChar() == 'e') && (readChar() == 'c') && | |
(readChar() == 'a') && (readChar() == 't') && | |
(readChar() == 'e') && (readChar() == 'd')) { | |
// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk. | |
c = readChar(); | |
if (Character.isWhitespace(c) || c == '*') { | |
return true; | |
} | |
} | |
} | |
continue nextLine; | |
} | |
} | |
return false; | |
} | |
} finally { | |
this.source = null; // release source as soon as finished | |
} | |
return this.deprecated; | |
} | |
public String toString() { | |
StringBuffer buffer = new StringBuffer(); | |
buffer.append("check javadoc: ").append(this.checkDocComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ | |
buffer.append("javadoc: ").append(this.docComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ | |
buffer.append(super.toString()); | |
return buffer.toString(); | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int) | |
*/ | |
protected Object createArgumentReference(char[] name, int dim, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException { | |
try { | |
TypeReference argTypeRef = (TypeReference) typeRef; | |
if (dim > 0) { | |
long pos = (((long) argTypeRef.sourceStart) << 32) + argTypeRef.sourceEnd; | |
if (typeRef instanceof JavadocSingleTypeReference) { | |
JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef; | |
argTypeRef = new JavadocArraySingleTypeReference(singleRef.token, dim, pos); | |
} else { | |
JavadocQualifiedTypeReference qualifRef = (JavadocQualifiedTypeReference) typeRef; | |
argTypeRef = new JavadocArrayQualifiedTypeReference(qualifRef, dim); | |
} | |
} | |
int argEnd = argTypeRef.sourceEnd; | |
if (dim > 0) argEnd = (int) dimPositions[dim-1]; | |
if (argNamePos >= 0) argEnd = (int) argNamePos; | |
return new JavadocArgumentExpression(name, argTypeRef.sourceStart, argEnd, argTypeRef); | |
} | |
catch (ClassCastException ex) { | |
throw new InvalidInputException(); | |
} | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#createFieldReference() | |
*/ | |
protected Object createFieldReference(Object receiver) throws InvalidInputException { | |
try { | |
// Get receiver type | |
TypeReference typeRef = (TypeReference) receiver; | |
if (typeRef == null) { | |
char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName(); | |
typeRef = new ImplicitDocTypeReference(name, this.memberStart); | |
} | |
// Create field | |
JavadocFieldReference field = new JavadocFieldReference(this.identifierStack[0], this.identifierPositionStack[0]); | |
field.receiver = typeRef; | |
field.tagSourceStart = this.tagSourceStart; | |
field.tagSourceEnd = this.tagSourceEnd; | |
field.tagValue = this.tagValue; | |
return field; | |
} | |
catch (ClassCastException ex) { | |
throw new InvalidInputException(); | |
} | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[]) | |
*/ | |
protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException { | |
try { | |
// Get receiver type | |
TypeReference typeRef = (TypeReference) receiver; | |
// Decide whether we have a constructor or not | |
boolean isConstructor = false; | |
if (typeRef == null) { | |
char[] name = this.sourceParser.compilationUnit.compilationResult.compilationUnit.getMainTypeName(); | |
isConstructor = CharOperation.equals(this.identifierStack[0], name); | |
typeRef = new ImplicitDocTypeReference(name, this.memberStart); | |
} else { | |
char[] name = null; | |
if (typeRef instanceof JavadocSingleTypeReference) { | |
name = ((JavadocSingleTypeReference)typeRef).token; | |
} else if (typeRef instanceof JavadocQualifiedTypeReference) { | |
char[][] tokens = ((JavadocQualifiedTypeReference)typeRef).tokens; | |
name = tokens[tokens.length-1]; | |
} else { | |
throw new InvalidInputException(); | |
} | |
isConstructor = CharOperation.equals(this.identifierStack[0], name); | |
} | |
// Create node | |
if (arguments == null) { | |
if (isConstructor) { | |
JavadocAllocationExpression alloc = new JavadocAllocationExpression(this.identifierPositionStack[0]); | |
alloc.type = typeRef; | |
alloc.tagValue = this.tagValue; | |
return alloc; | |
} else { | |
JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0]); | |
msg.receiver = typeRef; | |
msg.tagValue = this.tagValue; | |
return msg; | |
} | |
} else { | |
JavadocArgumentExpression[] expressions = new JavadocArgumentExpression[arguments.size()]; | |
arguments.toArray(expressions); | |
if (isConstructor) { | |
JavadocAllocationExpression alloc = new JavadocAllocationExpression(this.identifierPositionStack[0]); | |
alloc.arguments = expressions; | |
alloc.type = typeRef; | |
alloc.tagValue = this.tagValue; | |
return alloc; | |
} else { | |
JavadocMessageSend msg = new JavadocMessageSend(this.identifierStack[0], this.identifierPositionStack[0], expressions); | |
msg.receiver = typeRef; | |
msg.tagValue = this.tagValue; | |
return msg; | |
} | |
} | |
} | |
catch (ClassCastException ex) { | |
throw new InvalidInputException(); | |
} | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#createReturnStatement() | |
*/ | |
protected Object createReturnStatement() { | |
return new JavadocReturnStatement(this.scanner.getCurrentTokenStartPosition(), | |
this.scanner.getCurrentTokenEndPosition(), | |
this.scanner.getRawTokenSourceEnd()); | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#createTypeReference() | |
*/ | |
protected Object createTypeReference(int primitiveToken) { | |
TypeReference typeRef = null; | |
int size = this.identifierLengthStack[this.identifierLengthPtr--]; | |
if (size == 1) { // Single Type ref | |
typeRef = new JavadocSingleTypeReference( | |
this.identifierStack[this.identifierPtr], | |
this.identifierPositionStack[this.identifierPtr], | |
this.tagSourceStart, | |
this.tagSourceEnd); | |
} else if (size > 1) { // Qualified Type ref | |
char[][] tokens = new char[size][]; | |
System.arraycopy(this.identifierStack, this.identifierPtr - size + 1, tokens, 0, size); | |
long[] positions = new long[size]; | |
System.arraycopy(this.identifierPositionStack, this.identifierPtr - size + 1, positions, 0, size); | |
typeRef = new JavadocQualifiedTypeReference(tokens, positions, this.tagSourceStart, this.tagSourceEnd); | |
} | |
this.identifierPtr -= size; | |
return typeRef; | |
} | |
/* | |
* Parse @return tag declaration | |
*/ | |
protected boolean parseReturn() { | |
if (this.returnStatement == null) { | |
this.returnStatement = createReturnStatement(); | |
this.currentAstPtr = this.astPtr; | |
return true; | |
} | |
if (this.sourceParser != null) this.sourceParser.problemReporter().javadocDuplicatedReturnTag( | |
this.scanner.getCurrentTokenStartPosition(), | |
this.scanner.getCurrentTokenEndPosition()); | |
return false; | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#parseTag(int) | |
*/ | |
protected boolean parseTag(int previousPosition) throws InvalidInputException { | |
boolean valid = false; | |
// In case of previous return tag, set it to not empty if parsing an inline tag | |
if (this.currentAstPtr != -2 && this.returnStatement != null) { | |
this.currentAstPtr = -2; | |
JavadocReturnStatement javadocReturn = (JavadocReturnStatement) this.returnStatement; | |
javadocReturn.empty = javadocReturn.empty && !this.inlineTagStarted; | |
} | |
// Read tag name | |
int token = readTokenAndConsume(); | |
this.tagSourceStart = this.scanner.getCurrentTokenStartPosition(); | |
this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition(); | |
char[] tag = this.scanner.getCurrentIdentifierSource(); // first token is either an identifier or a keyword | |
// Decide which parse to perform depending on tag name | |
this.tagValue = NO_TAG_VALUE; | |
switch (token) { | |
case TerminalTokens.TokenNameIdentifier : | |
switch (tag[0]) { | |
case 'd': | |
if (CharOperation.equals(tag, TAG_DEPRECATED)) { | |
this.deprecated = true; | |
valid = true; | |
this.tagValue = TAG_DEPRECATED_VALUE; | |
} | |
break; | |
case 'i': | |
if (CharOperation.equals(tag, TAG_INHERITDOC)) { | |
// inhibits inherited flag when tags have been already stored | |
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51606 | |
// Note that for DOM_PARSER, nodes stack may be not empty even no '@' tag | |
// was encountered in comment. But it cannot be the case for COMPILER_PARSER | |
// and so is enough as it is only this parser which signals the missing tag warnings... | |
this.inherited = this.astPtr==-1; | |
valid = true; | |
this.tagValue = TAG_INHERITDOC_VALUE; | |
} | |
break; | |
case 'p': | |
if (CharOperation.equals(tag, TAG_PARAM)) { | |
this.tagValue = TAG_PARAM_VALUE; | |
valid = parseParam(); | |
} | |
break; | |
case 'e': | |
if (CharOperation.equals(tag, TAG_EXCEPTION)) { | |
this.tagValue = TAG_EXCEPTION_VALUE; | |
valid = parseThrows(); | |
} | |
break; | |
case 's': | |
if (CharOperation.equals(tag, TAG_SEE)) { | |
if (this.inlineTagStarted) { | |
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 | |
// Cannot have @see inside inline comment | |
valid = false; | |
if (this.sourceParser != null) | |
this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); | |
} else { | |
this.tagValue = TAG_SEE_VALUE; | |
valid = parseReference(); | |
} | |
} | |
break; | |
case 'l': | |
if (CharOperation.equals(tag, TAG_LINK)) { | |
this.tagValue = TAG_LINK_VALUE; | |
if (this.inlineTagStarted) { | |
valid= parseReference(); | |
} else { | |
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 | |
// Cannot have @link outside inline comment | |
valid = false; | |
if (this.sourceParser != null) | |
this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); | |
} | |
} else if (CharOperation.equals(tag, TAG_LINKPLAIN)) { | |
this.tagValue = TAG_LINKPLAIN_VALUE; | |
if (this.inlineTagStarted) { | |
valid = parseReference(); | |
} else { | |
valid = false; | |
if (this.sourceParser != null) | |
this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); | |
} | |
} | |
break; | |
case 'v': | |
if (CharOperation.equals(tag, TAG_VALUE) && this.sourceParser != null && this.sourceParser.options.sourceLevel >= ClassFileConstants.JDK1_5) { | |
this.tagValue = TAG_VALUE_VALUE; | |
if (this.inlineTagStarted) { | |
valid = parseReference(); | |
} else { | |
valid = false; | |
if (this.sourceParser != null) | |
this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); | |
} | |
} else { | |
createTag(); | |
} | |
break; | |
} | |
break; | |
case TerminalTokens.TokenNamereturn : | |
this.tagValue = TAG_RETURN_VALUE; | |
valid = parseReturn(); | |
/* verify characters after return tag (we're expecting text description) | |
if(!verifyCharsAfterReturnTag(this.index)) { | |
if (this.sourceParser != null) { | |
int end = this.starPosition == -1 || this.lineEnd<this.starPosition ? this.lineEnd : this.starPosition; | |
this.sourceParser.problemReporter().javadocEmptyReturnTag(this.tagSourceStart, end); | |
} | |
} | |
*/ | |
break; | |
case TerminalTokens.TokenNamethrows : | |
this.tagValue = TAG_THROWS_VALUE; | |
valid = parseThrows(); | |
break; | |
} | |
this.textStart = this.index; | |
return valid; | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#parseTagName() | |
*/ | |
protected void createTag() { | |
this.tagValue = TAG_OTHERS_VALUE; | |
} | |
/* | |
* Push a param name in ast node stack. | |
*/ | |
protected boolean pushParamName() { | |
// Create name reference | |
JavadocSingleNameReference nameRef = new JavadocSingleNameReference(this.scanner.getCurrentIdentifierSource(), | |
this.scanner.getCurrentTokenStartPosition(), | |
this.scanner.getCurrentTokenEndPosition()); | |
nameRef.tagSourceStart = this.tagSourceStart; | |
nameRef.tagSourceEnd = this.tagSourceEnd; | |
// Push ref on stack | |
if (this.astLengthPtr == -1) { // First push | |
pushOnAstStack(nameRef, true); | |
} else { | |
// Verify that no @throws has been declared before | |
for (int i=THROWS_TAG_EXPECTED_ORDER; i<=this.astLengthPtr; i+=ORDERED_TAGS_NUMBER) { | |
if (this.astLengthStack[i] != 0) { | |
if (this.sourceParser != null) this.sourceParser.problemReporter().javadocUnexpectedTag(this.tagSourceStart, this.tagSourceEnd); | |
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 | |
// store invalid param references in specific array | |
if (this.invalidParamReferencesPtr == -1l) { | |
this.invalidParamReferencesStack = new JavadocSingleNameReference[10]; | |
} | |
int stackLength = this.invalidParamReferencesStack.length; | |
if (++this.invalidParamReferencesPtr >= stackLength) { | |
System.arraycopy( | |
this.invalidParamReferencesStack, 0, | |
this.invalidParamReferencesStack = new JavadocSingleNameReference[stackLength + AstStackIncrement], 0, | |
stackLength); | |
} | |
this.invalidParamReferencesStack[this.invalidParamReferencesPtr] = nameRef; | |
return false; | |
} | |
} | |
switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { | |
case PARAM_TAG_EXPECTED_ORDER : | |
// previous push was a @param tag => push another param name | |
pushOnAstStack(nameRef, false); | |
break; | |
case SEE_TAG_EXPECTED_ORDER : | |
// previous push was a @see tag => push new param name | |
pushOnAstStack(nameRef, true); | |
break; | |
default: | |
return false; | |
} | |
} | |
return true; | |
} | |
/* | |
* Push a reference statement in ast node stack. | |
*/ | |
protected boolean pushSeeRef(Object statement) { | |
if (this.astLengthPtr == -1) { // First push | |
pushOnAstStack(null, true); | |
pushOnAstStack(null, true); | |
pushOnAstStack(statement, true); | |
} else { | |
switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { | |
case PARAM_TAG_EXPECTED_ORDER : | |
// previous push was a @param tag => push empty @throws tag and new @see tag | |
pushOnAstStack(null, true); | |
pushOnAstStack(statement, true); | |
break; | |
case THROWS_TAG_EXPECTED_ORDER : | |
// previous push was a @throws tag => push new @see tag | |
pushOnAstStack(statement, true); | |
break; | |
case SEE_TAG_EXPECTED_ORDER : | |
// previous push was a @see tag => push another @see tag | |
pushOnAstStack(statement, false); | |
break; | |
default: | |
return false; | |
} | |
} | |
return true; | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.wst.jsdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int) | |
*/ | |
protected void pushText(int start, int end) { | |
// In case of previous return tag, verify that text make it not empty | |
if (this.currentAstPtr != -2 && this.returnStatement != null) { | |
int position = this.index; | |
this.index = start; | |
boolean empty = true; | |
boolean star = false; | |
char ch = readChar(); | |
// Look for first character other than white or '*' | |
if (Character.isWhitespace(ch) || start>(this.tagSourceEnd+1)) { | |
while (this.index <= end && empty) { | |
if (!star) { | |
empty = Character.isWhitespace(ch) || ch == '*'; | |
star = ch == '*'; | |
} else if (ch != '*') { | |
empty = false; | |
break; | |
} | |
ch = readChar(); | |
} | |
} | |
// Store result in previous return tag | |
((JavadocReturnStatement)this.returnStatement).empty = empty; | |
// Reset position and current ast ptr if we are on a different tag than previous return one | |
this.index = position; | |
if (this.currentAstPtr != this.astPtr) { | |
this.currentAstPtr = -2; | |
} | |
} | |
} | |
/* | |
* Push a throws type ref in ast node stack. | |
*/ | |
protected boolean pushThrowName(Object typeRef) { | |
if (this.astLengthPtr == -1) { // First push | |
pushOnAstStack(null, true); | |
pushOnAstStack(typeRef, true); | |
} else { | |
switch (this.astLengthPtr % ORDERED_TAGS_NUMBER) { | |
case PARAM_TAG_EXPECTED_ORDER : | |
// previous push was a @param tag => push new @throws tag | |
pushOnAstStack(typeRef, true); | |
break; | |
case THROWS_TAG_EXPECTED_ORDER : | |
// previous push was a @throws tag => push another @throws tag | |
pushOnAstStack(typeRef, false); | |
break; | |
case SEE_TAG_EXPECTED_ORDER : | |
// previous push was a @see tag => push empty @param and new @throws tags | |
pushOnAstStack(null, true); | |
pushOnAstStack(typeRef, true); | |
break; | |
default: | |
return false; | |
} | |
} | |
return true; | |
} | |
/* | |
* Fill associated comment fields with ast nodes information stored in stack. | |
*/ | |
protected void updateDocComment() { | |
// Set inherited flag | |
this.docComment.inherited = this.inherited; | |
// Set return node if present | |
if (this.returnStatement != null) { | |
this.docComment.returnStatement = (JavadocReturnStatement) this.returnStatement; | |
} | |
// Copy array of invalid syntax param tags | |
if (this.invalidParamReferencesPtr >= 0) { | |
this.docComment.invalidParameters = new JavadocSingleNameReference[this.invalidParamReferencesPtr+1]; | |
System.arraycopy(this.invalidParamReferencesStack, 0, this.docComment.invalidParameters, 0, this.invalidParamReferencesPtr+1); | |
} | |
// If no nodes stored return | |
if (this.astLengthPtr == -1) { | |
return; | |
} | |
// Initialize arrays | |
int[] sizes = new int[ORDERED_TAGS_NUMBER]; | |
for (int i=0; i<=this.astLengthPtr; i++) { | |
sizes[i%ORDERED_TAGS_NUMBER] += this.astLengthStack[i]; | |
} | |
this.docComment.references = new Expression[sizes[SEE_TAG_EXPECTED_ORDER]]; | |
this.docComment.thrownExceptions = new TypeReference[sizes[THROWS_TAG_EXPECTED_ORDER]]; | |
this.docComment.parameters = new JavadocSingleNameReference[sizes[PARAM_TAG_EXPECTED_ORDER]]; | |
// Store nodes in arrays | |
while (this.astLengthPtr >= 0) { | |
int ptr = this.astLengthPtr % ORDERED_TAGS_NUMBER; | |
// Starting with the stack top, so get references (eg. Expression) coming from @see declarations | |
if (ptr == SEE_TAG_EXPECTED_ORDER) { | |
int size = this.astLengthStack[this.astLengthPtr--]; | |
for (int i=0; i<size; i++) { | |
this.docComment.references[--sizes[ptr]] = (Expression) this.astStack[this.astPtr--]; | |
} | |
} | |
// Then continuing with class names (eg. TypeReference) coming from @throw/@exception declarations | |
else if (ptr == THROWS_TAG_EXPECTED_ORDER) { | |
int size = this.astLengthStack[this.astLengthPtr--]; | |
for (int i=0; i<size; i++) { | |
this.docComment.thrownExceptions[--sizes[ptr]] = (TypeReference) this.astStack[this.astPtr--]; | |
} | |
} | |
// Finally, finishing with parameters nales (ie. Argument) coming from @param declaration | |
else if (ptr == PARAM_TAG_EXPECTED_ORDER) { | |
int size = this.astLengthStack[this.astLengthPtr--]; | |
for (int i=0; i<size; i++) { | |
this.docComment.parameters[--sizes[ptr]] = (JavadocSingleNameReference) this.astStack[this.astPtr--]; | |
} | |
} | |
} | |
} | |
} |