/*******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
public class DocumentElementParser extends Parser {
IDocumentElementRequestor requestor;
private int localIntPtr;
private int lastFieldEndPosition;
private int lastFieldBodyEndPosition;
private int typeStartPosition;
private long selectorSourcePositions;
private int typeDims;
private int extendsDim;
private int declarationSourceStart;
/* int[] stack for storing javadoc positions */
int[][] intArrayStack;
int intArrayPtr;
public DocumentElementParser(
final IDocumentElementRequestor requestor,
IProblemFactory problemFactory,
CompilerOptions options) {
super(new ProblemReporter(
DefaultErrorHandlingPolicies.exitAfterAllProblems(),
options,
problemFactory),
false);
this.requestor= requestor;
this.intArrayStack= new int[30][];
this.options= options;
this.javadocParser.checkDocComment= false;
setMethodsFullRecovery(false);
setStatementsRecovery(false);
}
/*
* Will clear the comment stack when looking
* for a potential JavaDoc which might contain @deprecated.
*
* Additionally, before investigating for @deprecated, retrieve the positions
* of the JavaDoc comments so as to notify requestor with them.
*/
public void checkComment() {
/* persisting javadoc positions */
pushOnIntArrayStack(getJavaDocPositions());
boolean deprecated= false;
int lastCommentIndex= -1;
int commentPtr= this.scanner.commentPtr;
//since jdk1.2 look only in the last java doc comment...
nextComment: for (lastCommentIndex= this.scanner.commentPtr; lastCommentIndex >= 0; lastCommentIndex--) {
// skip all non-javadoc comments or those which are after the last modifier
int commentSourceStart= this.scanner.commentStarts[lastCommentIndex];
if (commentSourceStart < 0 || // line comment
this.scanner.commentStops[lastCommentIndex] < 0 || // block comment
(this.modifiersSourceStart != -1 && this.modifiersSourceStart < commentSourceStart)) // the comment is after the modifier
{
continue nextComment;
}
// check comment
deprecated= this.javadocParser.checkDeprecation(lastCommentIndex);
break nextComment;
}
if (deprecated) {
checkAndSetModifiers(ClassFileConstants.AccDeprecated);
}
// modify the modifier source start to point at the first comment
if (commentPtr >= 0) {
this.declarationSourceStart= this.scanner.commentStarts[0];
if (this.declarationSourceStart < 0)
this.declarationSourceStart= -this.declarationSourceStart;
}
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeClassBodyDeclaration() {
// ClassBodyDeclaration ::= Diet Block
//push an Initializer
//optimize the push/pop
super.consumeClassBodyDeclaration();
Initializer initializer= (Initializer)this.astStack[this.astPtr];
this.requestor.acceptInitializer(
initializer.declarationSourceStart,
initializer.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
0,
this.modifiersSourceStart,
initializer.block.sourceStart,
initializer.block.sourceEnd);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeClassDeclaration() {
super.consumeClassDeclaration();
// we know that we have a TypeDeclaration on the top of the astStack
if (isLocalDeclaration()) {
// we ignore the local variable declarations
return;
}
this.requestor.exitClass(this.endStatementPosition, // '}' is the end of the body
((TypeDeclaration)this.astStack[this.astPtr]).declarationSourceEnd);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeClassHeader() {
//ClassHeader ::= $empty
super.consumeClassHeader();
if (isLocalDeclaration()) {
// we ignore the local variable declarations
this.intArrayPtr--;
return;
}
TypeDeclaration typeDecl= (TypeDeclaration)this.astStack[this.astPtr];
TypeReference[] superInterfaces= typeDecl.superInterfaces;
char[][] interfaceNames= null;
int[] interfaceNameStarts= null;
int[] interfaceNameEnds= null;
if (superInterfaces != null) {
int superInterfacesLength= superInterfaces.length;
interfaceNames= new char[superInterfacesLength][];
interfaceNameStarts= new int[superInterfacesLength];
interfaceNameEnds= new int[superInterfacesLength];
for (int i= 0; i < superInterfacesLength; i++) {
TypeReference superInterface= superInterfaces[i];
interfaceNames[i]= CharOperation.concatWith(superInterface.getTypeName(), '.');
interfaceNameStarts[i]= superInterface.sourceStart;
interfaceNameEnds[i]= superInterface.sourceEnd;
}
}
// flush the comments related to the class header
this.scanner.commentPtr= -1;
TypeReference superclass= typeDecl.superclass;
if (superclass == null) {
this.requestor.enterClass(
typeDecl.declarationSourceStart,
this.intArrayStack[this.intArrayPtr--],
typeDecl.modifiers,
typeDecl.modifiersSourceStart,
this.typeStartPosition,
typeDecl.name,
typeDecl.sourceStart,
typeDecl.sourceEnd,
null,
-1,
-1,
interfaceNames,
interfaceNameStarts,
interfaceNameEnds,
this.scanner.currentPosition - 1);
} else {
this.requestor.enterClass(
typeDecl.declarationSourceStart,
this.intArrayStack[this.intArrayPtr--],
typeDecl.modifiers,
typeDecl.modifiersSourceStart,
this.typeStartPosition,
typeDecl.name,
typeDecl.sourceStart,
typeDecl.sourceEnd,
CharOperation.concatWith(superclass.getTypeName(), '.'),
superclass.sourceStart,
superclass.sourceEnd,
interfaceNames,
interfaceNameStarts,
interfaceNameEnds,
this.scanner.currentPosition - 1);
}
}
protected void consumeClassHeaderName1() {
// ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
TypeDeclaration typeDecl= new TypeDeclaration(this.compilationUnit.compilationResult);
if (this.nestedMethod[this.nestedType] == 0) {
if (this.nestedType != 0) {
typeDecl.bits|= ASTNode.IsMemberType;
}
} else {
// Record that the block has a declaration for local types
typeDecl.bits|= ASTNode.IsLocalType;
markEnclosingMemberWithLocalType();
blockReal();
}
//highlight the name of the type
long pos= this.identifierPositionStack[this.identifierPtr];
typeDecl.sourceEnd= (int)pos;
typeDecl.sourceStart= (int)(pos >>> 32);
typeDecl.name= this.identifierStack[this.identifierPtr--];
this.identifierLengthPtr--;
//compute the declaration source too
// 'class' and 'interface' push an int position
this.typeStartPosition= typeDecl.declarationSourceStart= this.intStack[this.intPtr--];
this.intPtr--;
int declSourceStart= this.intStack[this.intPtr--];
typeDecl.modifiersSourceStart= this.intStack[this.intPtr--];
typeDecl.modifiers= this.intStack[this.intPtr--];
if (typeDecl.declarationSourceStart > declSourceStart) {
typeDecl.declarationSourceStart= declSourceStart;
}
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
typeDecl.annotations= new Annotation[length],
0,
length);
}
typeDecl.bodyStart= typeDecl.sourceEnd + 1;
pushOnAstStack(typeDecl);
// javadoc
typeDecl.javadoc= this.javadoc;
this.javadoc= null;
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeCompilationUnit() {
// CompilationUnit ::= EnterCompilationUnit PackageDeclarationopt ImportDeclarationsopt
this.requestor.exitCompilationUnit(this.scanner.source.length - 1);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeConstructorDeclaration() {
// ConstructorDeclaration ::= ConstructorHeader ConstructorBody
super.consumeConstructorDeclaration();
if (isLocalDeclaration()) {
// we ignore the local variable declarations
return;
}
ConstructorDeclaration cd= (ConstructorDeclaration)this.astStack[this.astPtr];
this.requestor.exitConstructor(this.endStatementPosition, cd.declarationSourceEnd);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeConstructorHeader() {
// ConstructorHeader ::= ConstructorHeaderName MethodHeaderParameters MethodHeaderThrowsClauseopt
super.consumeConstructorHeader();
if (isLocalDeclaration()) {
// we ignore the local variable declarations
this.intArrayPtr--;
return;
}
ConstructorDeclaration cd= (ConstructorDeclaration)this.astStack[this.astPtr];
Argument[] arguments= cd.arguments;
char[][] argumentTypes= null;
char[][] argumentNames= null;
int[] argumentTypeStarts= null;
int[] argumentTypeEnds= null;
int[] argumentNameStarts= null;
int[] argumentNameEnds= null;
if (arguments != null) {
int argumentLength= arguments.length;
argumentTypes= new char[argumentLength][];
argumentNames= new char[argumentLength][];
argumentNameStarts= new int[argumentLength];
argumentNameEnds= new int[argumentLength];
argumentTypeStarts= new int[argumentLength];
argumentTypeEnds= new int[argumentLength];
for (int i= 0; i < argumentLength; i++) {
Argument argument= arguments[i];
TypeReference argumentType= argument.type;
argumentTypes[i]= returnTypeName(argumentType);
argumentNames[i]= argument.name;
argumentNameStarts[i]= argument.sourceStart;
argumentNameEnds[i]= argument.sourceEnd;
argumentTypeStarts[i]= argumentType.sourceStart;
argumentTypeEnds[i]= argumentType.sourceEnd;
}
}
TypeReference[] thrownExceptions= cd.thrownExceptions;
char[][] exceptionTypes= null;
int[] exceptionTypeStarts= null;
int[] exceptionTypeEnds= null;
if (thrownExceptions != null) {
int thrownExceptionLength= thrownExceptions.length;
exceptionTypes= new char[thrownExceptionLength][];
exceptionTypeStarts= new int[thrownExceptionLength];
exceptionTypeEnds= new int[thrownExceptionLength];
for (int i= 0; i < thrownExceptionLength; i++) {
TypeReference exception= thrownExceptions[i];
exceptionTypes[i]= CharOperation.concatWith(exception.getTypeName(), '.');
exceptionTypeStarts[i]= exception.sourceStart;
exceptionTypeEnds[i]= exception.sourceEnd;
}
}
this.requestor
.enterConstructor(
cd.declarationSourceStart,
this.intArrayStack[this.intArrayPtr--],
cd.modifiers,
cd.modifiersSourceStart,
cd.selector,
cd.sourceStart,
(int)(this.selectorSourcePositions & 0xFFFFFFFFL),
// retrieve the source end of the name
argumentTypes,
argumentTypeStarts,
argumentTypeEnds,
argumentNames,
argumentNameStarts,
argumentNameEnds,
this.rParenPos,
// right parenthesis
exceptionTypes,
exceptionTypeStarts,
exceptionTypeEnds,
this.scanner.currentPosition - 1);
}
protected void consumeConstructorHeaderName() {
// ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
ConstructorDeclaration cd= new ConstructorDeclaration(this.compilationUnit.compilationResult);
//name -- this is not really revelant but we do .....
cd.selector= this.identifierStack[this.identifierPtr];
this.selectorSourcePositions= this.identifierPositionStack[this.identifierPtr--];
this.identifierLengthPtr--;
//modifiers
cd.declarationSourceStart= this.intStack[this.intPtr--];
cd.modifiersSourceStart= this.intStack[this.intPtr--];
cd.modifiers= this.intStack[this.intPtr--];
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
cd.annotations= new Annotation[length],
0,
length);
}
// javadoc
cd.javadoc= this.javadoc;
this.javadoc= null;
//highlight starts at the selector starts
cd.sourceStart= (int)(this.selectorSourcePositions >>> 32);
pushOnAstStack(cd);
cd.sourceEnd= this.lParenPos;
cd.bodyStart= this.lParenPos + 1;
}
protected void consumeDefaultModifiers() {
checkComment(); // might update modifiers with AccDeprecated
pushOnIntStack(this.modifiers); // modifiers
pushOnIntStack(-1);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.scanner.startPosition);
resetModifiers();
pushOnExpressionStackLengthStack(0);
}
protected void consumeDiet() {
// Diet ::= $empty
super.consumeDiet();
/* persisting javadoc positions
* Will be consume in consumeClassBodyDeclaration
*/
pushOnIntArrayStack(getJavaDocPositions());
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeEnterCompilationUnit() {
// EnterCompilationUnit ::= $empty
this.requestor.enterCompilationUnit();
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeEnterVariable() {
// EnterVariable ::= $empty
boolean isLocalDeclaration= isLocalDeclaration();
if (!isLocalDeclaration && (this.variablesCounter[this.nestedType] != 0)) {
this.requestor.exitField(this.lastFieldBodyEndPosition, this.lastFieldEndPosition);
}
char[] varName= this.identifierStack[this.identifierPtr];
long namePosition= this.identifierPositionStack[this.identifierPtr--];
int extendedTypeDimension= this.intStack[this.intPtr--];
AbstractVariableDeclaration declaration;
if (this.nestedMethod[this.nestedType] != 0) {
// create the local variable declarations
declaration=
new LocalDeclaration(varName, (int)(namePosition >>> 32), (int)namePosition);
} else {
// create the field declaration
declaration=
new FieldDeclaration(varName, (int)(namePosition >>> 32), (int)namePosition);
}
this.identifierLengthPtr--;
TypeReference type;
int variableIndex= this.variablesCounter[this.nestedType];
int typeDim= 0;
if (variableIndex == 0) {
// first variable of the declaration (FieldDeclaration or LocalDeclaration)
if (this.nestedMethod[this.nestedType] != 0) {
// local declaration
declaration.declarationSourceStart= this.intStack[this.intPtr--];
declaration.modifiersSourceStart= this.intStack[this.intPtr--];
declaration.modifiers= this.intStack[this.intPtr--];
type= getTypeReference(typeDim= this.intStack[this.intPtr--]); // type dimension
pushOnAstStack(type);
} else {
// field declaration
type= getTypeReference(typeDim= this.intStack[this.intPtr--]); // type dimension
pushOnAstStack(type);
declaration.declarationSourceStart= this.intStack[this.intPtr--];
declaration.modifiersSourceStart= this.intStack[this.intPtr--];
declaration.modifiers= this.intStack[this.intPtr--];
}
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
declaration.annotations= new Annotation[length],
0,
length);
}
} else {
type= (TypeReference)this.astStack[this.astPtr - variableIndex];
typeDim= type.dimensions();
AbstractVariableDeclaration previousVariable=
(AbstractVariableDeclaration)this.astStack[this.astPtr];
declaration.declarationSourceStart= previousVariable.declarationSourceStart;
declaration.modifiers= previousVariable.modifiers;
declaration.modifiersSourceStart= previousVariable.modifiersSourceStart;
final Annotation[] annotations= previousVariable.annotations;
if (annotations != null) {
final int annotationsLength= annotations.length;
System.arraycopy(annotations, 0, declaration.annotations= new Annotation[annotationsLength], 0, annotationsLength);
}
}
this.localIntPtr= this.intPtr;
if (extendedTypeDimension == 0) {
declaration.type= type;
} else {
int dimension= typeDim + extendedTypeDimension;
declaration.type= copyDims(type, dimension);
}
this.variablesCounter[this.nestedType]++;
this.nestedMethod[this.nestedType]++;
pushOnAstStack(declaration);
int[] javadocPositions= this.intArrayStack[this.intArrayPtr];
if (!isLocalDeclaration) {
this.requestor
.enterField(
declaration.declarationSourceStart,
javadocPositions,
declaration.modifiers,
declaration.modifiersSourceStart,
returnTypeName(declaration.type),
type.sourceStart,
type.sourceEnd,
this.typeDims,
varName,
(int)(namePosition >>> 32),
(int)namePosition,
extendedTypeDimension,
extendedTypeDimension == 0 ? -1 : this.endPosition);
}
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeExitVariableWithInitialization() {
// ExitVariableWithInitialization ::= $empty
// the scanner is located after the comma or the semi-colon.
// we want to include the comma or the semi-colon
super.consumeExitVariableWithInitialization();
this.nestedMethod[this.nestedType]--;
this.lastFieldEndPosition= this.scanner.currentPosition - 1;
this.lastFieldBodyEndPosition= ((AbstractVariableDeclaration)this.astStack[this.astPtr]).initialization.sourceEnd;
}
protected void consumeExitVariableWithoutInitialization() {
// ExitVariableWithoutInitialization ::= $empty
// do nothing by default
super.consumeExitVariableWithoutInitialization();
this.nestedMethod[this.nestedType]--;
this.lastFieldEndPosition= this.scanner.currentPosition - 1;
this.lastFieldBodyEndPosition= this.scanner.startPosition - 1;
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeFieldDeclaration() {
// See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code
// FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
// the super.consumeFieldDeclaration will reinitialize the variableCounter[nestedType]
int variableIndex= this.variablesCounter[this.nestedType];
super.consumeFieldDeclaration();
this.intArrayPtr--;
if (isLocalDeclaration())
return;
if (variableIndex != 0) {
this.requestor.exitField(this.lastFieldBodyEndPosition, this.lastFieldEndPosition);
}
}
protected void consumeFormalParameter(boolean isVarArgs) {
// FormalParameter ::= Type VariableDeclaratorId ==> false
// FormalParameter ::= Modifiers Type VariableDeclaratorId ==> true
/*
astStack :
identifierStack : type identifier
intStack : dim dim
==>
astStack : Argument
identifierStack :
intStack :
*/
this.identifierLengthPtr--;
char[] parameterName= this.identifierStack[this.identifierPtr];
long namePositions= this.identifierPositionStack[this.identifierPtr--];
int extendedDimensions= this.intStack[this.intPtr--];
int endOfEllipsis= 0;
if (isVarArgs) {
endOfEllipsis= this.intStack[this.intPtr--];
}
int firstDimensions= this.intStack[this.intPtr--];
final int typeDimensions= firstDimensions + extendedDimensions;
TypeReference type= getTypeReference(typeDimensions);
if (isVarArgs) {
type= copyDims(type, typeDimensions + 1);
if (extendedDimensions == 0) {
type.sourceEnd= endOfEllipsis;
}
type.bits|= ASTNode.IsVarArgs; // set isVarArgs
}
this.intPtr-= 3;
Argument arg=
new Argument(
parameterName,
namePositions,
type,
this.intStack[this.intPtr + 1]);// modifiers
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
arg.annotations= new Annotation[length],
0,
length);
}
pushOnAstStack(arg);
this.intArrayPtr--;
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeInterfaceDeclaration() {
super.consumeInterfaceDeclaration();
// we know that we have a TypeDeclaration on the top of the astStack
if (isLocalDeclaration()) {
// we ignore the local variable declarations
return;
}
this.requestor.exitInterface(this.endStatementPosition, // the '}' is the end of the body
((TypeDeclaration)this.astStack[this.astPtr]).declarationSourceEnd);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeInterfaceHeader() {
//InterfaceHeader ::= $empty
super.consumeInterfaceHeader();
if (isLocalDeclaration()) {
// we ignore the local variable declarations
this.intArrayPtr--;
return;
}
TypeDeclaration typeDecl= (TypeDeclaration)this.astStack[this.astPtr];
TypeReference[] superInterfaces= typeDecl.superInterfaces;
char[][] interfaceNames= null;
int[] interfaceNameStarts= null;
int[] interfacenameEnds= null;
int superInterfacesLength= 0;
if (superInterfaces != null) {
superInterfacesLength= superInterfaces.length;
interfaceNames= new char[superInterfacesLength][];
interfaceNameStarts= new int[superInterfacesLength];
interfacenameEnds= new int[superInterfacesLength];
}
if (superInterfaces != null) {
for (int i= 0; i < superInterfacesLength; i++) {
TypeReference superInterface= superInterfaces[i];
interfaceNames[i]= CharOperation.concatWith(superInterface.getTypeName(), '.');
interfaceNameStarts[i]= superInterface.sourceStart;
interfacenameEnds[i]= superInterface.sourceEnd;
}
}
// flush the comments related to the interface header
this.scanner.commentPtr= -1;
this.requestor.enterInterface(
typeDecl.declarationSourceStart,
this.intArrayStack[this.intArrayPtr--],
typeDecl.modifiers,
typeDecl.modifiersSourceStart,
this.typeStartPosition,
typeDecl.name,
typeDecl.sourceStart,
typeDecl.sourceEnd,
interfaceNames,
interfaceNameStarts,
interfacenameEnds,
this.scanner.currentPosition - 1);
}
protected void consumeInterfaceHeaderName1() {
// InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
TypeDeclaration typeDecl= new TypeDeclaration(this.compilationUnit.compilationResult);
if (this.nestedMethod[this.nestedType] == 0) {
if (this.nestedType != 0) {
typeDecl.bits|= ASTNode.IsMemberType;
}
} else {
// Record that the block has a declaration for local types
typeDecl.bits|= ASTNode.IsLocalType;
markEnclosingMemberWithLocalType();
blockReal();
}
//highlight the name of the type
long pos= this.identifierPositionStack[this.identifierPtr];
typeDecl.sourceEnd= (int)pos;
typeDecl.sourceStart= (int)(pos >>> 32);
typeDecl.name= this.identifierStack[this.identifierPtr--];
this.identifierLengthPtr--;
//compute the declaration source too
// 'class' and 'interface' push an int position
this.typeStartPosition= typeDecl.declarationSourceStart= this.intStack[this.intPtr--];
this.intPtr--;
int declSourceStart= this.intStack[this.intPtr--];
typeDecl.modifiersSourceStart= this.intStack[this.intPtr--];
typeDecl.modifiers= this.intStack[this.intPtr--] | ClassFileConstants.AccInterface;
if (typeDecl.declarationSourceStart > declSourceStart) {
typeDecl.declarationSourceStart= declSourceStart;
}
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
typeDecl.annotations= new Annotation[length],
0,
length);
}
typeDecl.bodyStart= typeDecl.sourceEnd + 1;
pushOnAstStack(typeDecl);
// javadoc
typeDecl.javadoc= this.javadoc;
this.javadoc= null;
}
protected void consumeInternalCompilationUnit() {
// InternalCompilationUnit ::= PackageDeclaration
// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
// InternalCompilationUnit ::= ImportDeclarations ReduceImports
}
protected void consumeInternalCompilationUnitWithTypes() {
// InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
// InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
// InternalCompilationUnit ::= TypeDeclarations
// InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
// consume type declarations
int length;
if ((length= this.astLengthStack[this.astLengthPtr--]) != 0) {
this.compilationUnit.types= new TypeDeclaration[length];
this.astPtr-= length;
System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
}
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeLocalVariableDeclaration() {
// See consumeLocalVariableDeclarationDefaultModifier() in case of change: duplicated code
// FieldDeclaration ::= Modifiersopt Type VariableDeclarators ';'
super.consumeLocalVariableDeclaration();
this.intArrayPtr--;
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeMethodDeclaration(boolean isNotAbstract) {
// MethodDeclaration ::= MethodHeader MethodBody
// AbstractMethodDeclaration ::= MethodHeader ';'
super.consumeMethodDeclaration(isNotAbstract);
if (isLocalDeclaration()) {
// we ignore the local variable declarations
return;
}
MethodDeclaration md= (MethodDeclaration)this.astStack[this.astPtr];
this.requestor.exitMethod(this.endStatementPosition, md.declarationSourceEnd);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeMethodHeader() {
// MethodHeader ::= MethodHeaderName MethodHeaderParameters MethodHeaderExtendedDims ThrowsClauseopt
super.consumeMethodHeader();
if (isLocalDeclaration()) {
// we ignore the local variable declarations
this.intArrayPtr--;
return;
}
MethodDeclaration md= (MethodDeclaration)this.astStack[this.astPtr];
TypeReference returnType= md.returnType;
char[] returnTypeName= returnTypeName(returnType);
Argument[] arguments= md.arguments;
char[][] argumentTypes= null;
char[][] argumentNames= null;
int[] argumentTypeStarts= null;
int[] argumentTypeEnds= null;
int[] argumentNameStarts= null;
int[] argumentNameEnds= null;
if (arguments != null) {
int argumentLength= arguments.length;
argumentTypes= new char[argumentLength][];
argumentNames= new char[argumentLength][];
argumentNameStarts= new int[argumentLength];
argumentNameEnds= new int[argumentLength];
argumentTypeStarts= new int[argumentLength];
argumentTypeEnds= new int[argumentLength];
for (int i= 0; i < argumentLength; i++) {
Argument argument= arguments[i];
TypeReference argumentType= argument.type;
argumentTypes[i]= returnTypeName(argumentType);
argumentNames[i]= argument.name;
argumentNameStarts[i]= argument.sourceStart;
argumentNameEnds[i]= argument.sourceEnd;
argumentTypeStarts[i]= argumentType.sourceStart;
argumentTypeEnds[i]= argumentType.sourceEnd;
}
}
TypeReference[] thrownExceptions= md.thrownExceptions;
char[][] exceptionTypes= null;
int[] exceptionTypeStarts= null;
int[] exceptionTypeEnds= null;
if (thrownExceptions != null) {
int thrownExceptionLength= thrownExceptions.length;
exceptionTypeStarts= new int[thrownExceptionLength];
exceptionTypeEnds= new int[thrownExceptionLength];
exceptionTypes= new char[thrownExceptionLength][];
for (int i= 0; i < thrownExceptionLength; i++) {
TypeReference exception= thrownExceptions[i];
exceptionTypes[i]= CharOperation.concatWith(exception.getTypeName(), '.');
exceptionTypeStarts[i]= exception.sourceStart;
exceptionTypeEnds[i]= exception.sourceEnd;
}
}
this.requestor
.enterMethod(
md.declarationSourceStart,
this.intArrayStack[this.intArrayPtr--],
md.modifiers,
md.modifiersSourceStart,
returnTypeName,
returnType.sourceStart,
returnType.sourceEnd,
this.typeDims,
md.selector,
md.sourceStart,
(int)(this.selectorSourcePositions & 0xFFFFFFFFL),
argumentTypes,
argumentTypeStarts,
argumentTypeEnds,
argumentNames,
argumentNameStarts,
argumentNameEnds,
this.rParenPos,
this.extendsDim,
this.extendsDim == 0 ? -1 : this.endPosition,
exceptionTypes,
exceptionTypeStarts,
exceptionTypeEnds,
this.scanner.currentPosition - 1);
}
protected void consumeMethodHeaderExtendedDims() {
// MethodHeaderExtendedDims ::= Dimsopt
// now we update the returnType of the method
MethodDeclaration md= (MethodDeclaration)this.astStack[this.astPtr];
int extendedDims= this.intStack[this.intPtr--];
this.extendsDim= extendedDims;
if (extendedDims != 0) {
TypeReference returnType= md.returnType;
md.sourceEnd= this.endPosition;
int dims= returnType.dimensions() + extendedDims;
md.returnType= copyDims(returnType, dims);
if (this.currentToken == TokenNameLBRACE) {
md.bodyStart= this.endPosition + 1;
}
}
}
protected void consumeMethodHeaderName(boolean isAnnotationMethod) {
// MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
MethodDeclaration md= null;
if (isAnnotationMethod) {
md= new AnnotationMethodDeclaration(this.compilationUnit.compilationResult);
} else {
md= new MethodDeclaration(this.compilationUnit.compilationResult);
}
//name
md.selector= this.identifierStack[this.identifierPtr];
this.selectorSourcePositions= this.identifierPositionStack[this.identifierPtr--];
this.identifierLengthPtr--;
//type
md.returnType= getTypeReference(this.typeDims= this.intStack[this.intPtr--]);
//modifiers
md.declarationSourceStart= this.intStack[this.intPtr--];
md.modifiersSourceStart= this.intStack[this.intPtr--];
md.modifiers= this.intStack[this.intPtr--];
// consume annotations
int length;
if ((length= this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
System.arraycopy(
this.expressionStack,
(this.expressionPtr-= length) + 1,
md.annotations= new Annotation[length],
0,
length);
}
// javadoc
md.javadoc= this.javadoc;
this.javadoc= null;
//highlight starts at selector start
md.sourceStart= (int)(this.selectorSourcePositions >>> 32);
pushOnAstStack(md);
md.bodyStart= this.scanner.currentPosition - 1;
}
protected void consumeModifiers() {
checkComment(); // might update modifiers with AccDeprecated
pushOnIntStack(this.modifiers); // modifiers
pushOnIntStack(this.modifiersSourceStart);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.modifiersSourceStart);
resetModifiers();
}
protected void consumePackageComment() {
// get possible comment for syntax since 1.5
if (this.options.sourceLevel >= ClassFileConstants.JDK1_5) {
checkComment();
} else {
pushOnIntArrayStack(getJavaDocPositions());
}
resetModifiers();
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumePackageDeclarationName() {
/*
* Javadoc positions are persisted in consumePackageComment
*/
super.consumePackageDeclarationName();
ImportReference importReference= this.compilationUnit.currentPackage;
this.requestor.acceptPackage(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumePackageDeclarationNameWithModifiers() {
super.consumePackageDeclarationNameWithModifiers();
ImportReference importReference= this.compilationUnit.currentPackage;
this.requestor.acceptPackage(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart);
}
protected void consumePushModifiers() {
checkComment(); // might update modifiers with AccDeprecated
pushOnIntStack(this.modifiers); // modifiers
if (this.modifiersSourceStart < 0) {
pushOnIntStack(-1);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.scanner.startPosition);
} else {
pushOnIntStack(this.modifiersSourceStart);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.modifiersSourceStart);
}
resetModifiers();
pushOnExpressionStackLengthStack(0);
}
protected void consumePushRealModifiers() {
checkComment(); // might update modifiers with AccDeprecated
pushOnIntStack(this.modifiers); // modifiers
if (this.modifiersSourceStart < 0) {
pushOnIntStack(-1);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.scanner.startPosition);
} else {
pushOnIntStack(this.modifiersSourceStart);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.modifiersSourceStart);
}
resetModifiers();
}
protected void consumeSingleStaticImportDeclarationName() {
// SingleTypeImportDeclarationName ::= 'import' 'static' Name
/* persisting javadoc positions */
pushOnIntArrayStack(getJavaDocPositions());
super.consumeSingleStaticImportDeclarationName();
ImportReference importReference= (ImportReference)this.astStack[this.astPtr];
this.requestor.acceptImport(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart,
false,
ClassFileConstants.AccStatic);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeSingleTypeImportDeclarationName() {
// SingleTypeImportDeclarationName ::= 'import' Name
/* persisting javadoc positions */
pushOnIntArrayStack(getJavaDocPositions());
super.consumeSingleTypeImportDeclarationName();
ImportReference importReference= (ImportReference)this.astStack[this.astPtr];
this.requestor.acceptImport(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart,
false,
ClassFileConstants.AccDefault);
}
protected void consumeStaticImportOnDemandDeclarationName() {
// SingleTypeImportDeclarationName ::= 'import' 'static' Name '.' '*'
/* persisting javadoc positions */
pushOnIntArrayStack(getJavaDocPositions());
super.consumeStaticImportOnDemandDeclarationName();
ImportReference importReference= (ImportReference)this.astStack[this.astPtr];
this.requestor.acceptImport(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart,
true,
ClassFileConstants.AccStatic);
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeStaticInitializer() {
// StaticInitializer ::= StaticOnly Block
//push an Initializer
//optimize the push/pop
super.consumeStaticInitializer();
Initializer initializer= (Initializer)this.astStack[this.astPtr];
this.requestor.acceptInitializer(
initializer.declarationSourceStart,
initializer.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
ClassFileConstants.AccStatic,
this.intStack[this.intPtr--],
initializer.block.sourceStart,
initializer.declarationSourceEnd);
}
protected void consumeStaticOnly() {
// StaticOnly ::= 'static'
checkComment(); // might update declaration source start
pushOnIntStack(this.modifiersSourceStart);
pushOnIntStack(this.scanner.currentPosition);
pushOnIntStack(this.declarationSourceStart >= 0 ? this.declarationSourceStart : this.modifiersSourceStart);
jumpOverMethodBody();
this.nestedMethod[this.nestedType]++;
resetModifiers();
}
/*
*
* INTERNAL USE-ONLY
*/
protected void consumeTypeImportOnDemandDeclarationName() {
// TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
/* persisting javadoc positions */
pushOnIntArrayStack(getJavaDocPositions());
super.consumeTypeImportOnDemandDeclarationName();
ImportReference importReference= (ImportReference)this.astStack[this.astPtr];
this.requestor.acceptImport(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
this.intArrayStack[this.intArrayPtr--],
CharOperation.concatWith(importReference.getImportName(), '.'),
importReference.sourceStart,
true,
ClassFileConstants.AccDefault);
}
/*
* Flush javadocs defined prior to a given positions.
*
* Note: javadocs are stacked in syntactical order
*
* Either answer given <position>, or the end position of a comment line
* immediately following the <position> (same line)
*
* e.g.
* void foo(){
* } // end of method foo
*/
public int flushCommentsDefinedPriorTo(int position) {
return this.lastFieldEndPosition= super.flushCommentsDefinedPriorTo(position);
}
public CompilationUnitDeclaration endParse(int act) {
if (this.scanner.recordLineSeparator) {
this.requestor.acceptLineSeparatorPositions(this.scanner.getLineEnds());
}
return super.endParse(act);
}
public void initialize(boolean initializeNLS) {
//positionning the parser for a new compilation unit
//avoiding stack reallocation and all that....
super.initialize(initializeNLS);
this.intArrayPtr= -1;
}
public void initialize() {
//positionning the parser for a new compilation unit
//avoiding stack reallocation and all that....
super.initialize();
this.intArrayPtr= -1;
}
/*
*
* INTERNAL USE-ONLY
*/
private boolean isLocalDeclaration() {
int nestedDepth= this.nestedType;
while (nestedDepth >= 0) {
if (this.nestedMethod[nestedDepth] != 0) {
return true;
}
nestedDepth--;
}
return false;
}
protected void parse() {
this.diet= true;
super.parse();
}
/*
* Investigate one entire unit.
*/
public void parseCompilationUnit(ICompilationUnit unit) {
char[] regionSource= unit.getContents();
try {
initialize(true);
goForCompilationUnit();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one constructor declaration.
*/
public void parseConstructor(char[] regionSource) {
try {
initialize();
goForClassBodyDeclarations();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one field declaration statement (might have multiple declarations in it).
*/
public void parseField(char[] regionSource) {
try {
initialize();
goForFieldDeclaration();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one import statement declaration.
*/
public void parseImport(char[] regionSource) {
try {
initialize();
goForImportDeclaration();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one initializer declaration.
* regionSource need to content exactly an initializer declaration.
* e.g: static { i = 4; }
* { name = "test"; }
*/
public void parseInitializer(char[] regionSource) {
try {
initialize();
goForInitializer();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one method declaration.
*/
public void parseMethod(char[] regionSource) {
try {
initialize();
goForGenericMethodDeclaration();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one package statement declaration.
*/
public void parsePackage(char[] regionSource) {
try {
initialize();
goForPackageDeclaration();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/*
* Investigate one type declaration, its fields, methods and member types.
*/
public void parseType(char[] regionSource) {
try {
initialize();
goForTypeDeclaration();
this.referenceContext=
this.compilationUnit=
new CompilationUnitDeclaration(
problemReporter(),
new CompilationResult(regionSource, 0, 0, this.options.maxProblemsPerUnit),
regionSource.length);
this.scanner.resetTo(0, regionSource.length);
this.scanner.setSource(regionSource);
parse();
} catch (AbortCompilation ex) {
// ignore this exception
}
}
/**
* Returns this parser's problem reporter initialized with its reference context. Also it is
* assumed that a problem is going to be reported, so initializes the compilation result's line
* positions.
*
* @return ProblemReporter
*/
public ProblemReporter problemReporter() {
this.problemReporter.referenceContext= this.referenceContext;
return this.problemReporter;
}
protected void pushOnIntArrayStack(int[] positions) {
int stackLength= this.intArrayStack.length;
if (++this.intArrayPtr >= stackLength) {
System.arraycopy(
this.intArrayStack, 0,
this.intArrayStack= new int[stackLength + StackIncrement][], 0,
stackLength);
}
this.intArrayStack[this.intArrayPtr]= positions;
}
protected void resetModifiers() {
super.resetModifiers();
this.declarationSourceStart= -1;
}
/*
* Syntax error was detected. Will attempt to perform some recovery action in order
* to resume to the regular parse loop.
*/
protected boolean resumeOnSyntaxError() {
return false;
}
/*
* Answer a char array representation of the type name formatted like:
* - type name + dimensions
* Example:
* "A[][]".toCharArray()
* "java.lang.String".toCharArray()
*/
private char[] returnTypeName(TypeReference type) {
int dimension= type.dimensions();
if (dimension != 0) {
char[] dimensionsArray= new char[dimension * 2];
for (int i= 0; i < dimension; i++) {
dimensionsArray[i * 2]= '[';
dimensionsArray[(i * 2) + 1]= ']';
}
return CharOperation.concat(
CharOperation.concatWith(type.getTypeName(), '.'),
dimensionsArray);
}
return CharOperation.concatWith(type.getTypeName(), '.');
}
public String toString() {
StringBuffer buffer= new StringBuffer();
buffer.append("intArrayPtr = " + this.intArrayPtr + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(super.toString());
return buffer.toString();
}
/**
* INTERNAL USE ONLY
*/
protected TypeReference typeReference(
int dim,
int localIdentifierPtr,
int localIdentifierLengthPtr) {
/* build a Reference on a variable that may be qualified or not
* This variable is a type reference and dim will be its dimensions.
* We don't have any side effect on the stacks' pointers.
*/
int length;
TypeReference ref;
if ((length= this.identifierLengthStack[localIdentifierLengthPtr]) == 1) {
// single variable reference
if (dim == 0) {
ref=
new SingleTypeReference(
this.identifierStack[localIdentifierPtr],
this.identifierPositionStack[localIdentifierPtr--]);
} else {
ref=
new ArrayTypeReference(
this.identifierStack[localIdentifierPtr],
dim,
this.identifierPositionStack[localIdentifierPtr--]);
ref.sourceEnd= this.endPosition;
}
} else {
if (length < 0) { //flag for precompiled type reference on base types
ref= TypeReference.baseTypeReference(-length, dim);
ref.sourceStart= this.intStack[this.localIntPtr--];
if (dim == 0) {
ref.sourceEnd= this.intStack[this.localIntPtr--];
} else {
this.localIntPtr--;
ref.sourceEnd= this.endPosition;
}
} else { //Qualified variable reference
char[][] tokens= new char[length][];
localIdentifierPtr-= length;
long[] positions= new long[length];
System.arraycopy(this.identifierStack, localIdentifierPtr + 1, tokens, 0, length);
System.arraycopy(
this.identifierPositionStack,
localIdentifierPtr + 1,
positions,
0,
length);
if (dim == 0)
ref= new QualifiedTypeReference(tokens, positions);
else
ref= new ArrayQualifiedTypeReference(tokens, dim, positions);
}
}
return ref;
}
}