/*******************************************************************************
* 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.parser;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Block;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
/**
* Internal type structure for parsing recovery
*/
public class RecoveredType extends RecoveredStatement implements TerminalTokens {
public static final int MAX_TYPE_DEPTH= 256;
public TypeDeclaration typeDeclaration;
public RecoveredAnnotation[] annotations;
public int annotationCount;
public int modifiers;
public int modifiersStart;
public RecoveredType[] memberTypes;
public int memberTypeCount;
public RecoveredField[] fields;
public int fieldCount;
public RecoveredMethod[] methods;
public int methodCount;
public boolean preserveContent= false; // only used for anonymous types
public int bodyEnd;
public boolean insideEnumConstantPart= false;
public TypeParameter[] pendingTypeParameters;
public int pendingTypeParametersStart;
int pendingModifiers;
int pendingModifersSourceStart= -1;
RecoveredAnnotation[] pendingAnnotations;
int pendingAnnotationCount;
public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance) {
super(typeDeclaration, parent, bracketBalance);
this.typeDeclaration= typeDeclaration;
if (typeDeclaration.allocation != null && typeDeclaration.allocation.type == null) {
// an enum constant body can not exist if there is no opening brace
this.foundOpeningBrace= true;
} else {
this.foundOpeningBrace= !bodyStartsAtHeaderEnd();
}
this.insideEnumConstantPart= TypeDeclaration.kind(typeDeclaration.modifiers) == TypeDeclaration.ENUM_DECL;
if (this.foundOpeningBrace) {
this.bracketBalance++;
}
this.preserveContent= parser().methodRecoveryActivated || parser().statementRecoveryActivated;
}
public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) {
/* do not consider a method starting passed the type end (if set)
it must be belonging to an enclosing type */
if (this.typeDeclaration.declarationSourceEnd != 0
&& methodDeclaration.declarationSourceStart > this.typeDeclaration.declarationSourceEnd) {
this.pendingTypeParameters= null;
resetPendingModifiers();
return this.parent.add(methodDeclaration, bracketBalanceValue);
}
if (this.methods == null) {
this.methods= new RecoveredMethod[5];
this.methodCount= 0;
} else {
if (this.methodCount == this.methods.length) {
System.arraycopy(
this.methods,
0,
(this.methods= new RecoveredMethod[2 * this.methodCount]),
0,
this.methodCount);
}
}
RecoveredMethod element= new RecoveredMethod(methodDeclaration, this, bracketBalanceValue, this.recoveringParser);
this.methods[this.methodCount++]= element;
if (this.pendingTypeParameters != null) {
element.attach(this.pendingTypeParameters, this.pendingTypeParametersStart);
this.pendingTypeParameters= null;
}
if (this.pendingAnnotationCount > 0) {
element.attach(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
this.insideEnumConstantPart= false;
/* consider that if the opening brace was not found, it is there */
if (!this.foundOpeningBrace) {
this.foundOpeningBrace= true;
this.bracketBalance++;
}
/* if method not finished, then method becomes current */
if (methodDeclaration.declarationSourceEnd == 0)
return element;
return this;
}
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
this.pendingTypeParameters= null;
resetPendingModifiers();
int mods= ClassFileConstants.AccDefault;
if (parser().recoveredStaticInitializerStart != 0) {
mods= ClassFileConstants.AccStatic;
}
return this.add(new Initializer(nestedBlockDeclaration, mods), bracketBalanceValue);
}
public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
this.pendingTypeParameters= null;
/* do not consider a field starting passed the type end (if set)
it must be belonging to an enclosing type */
if (this.typeDeclaration.declarationSourceEnd != 0
&& fieldDeclaration.declarationSourceStart > this.typeDeclaration.declarationSourceEnd) {
resetPendingModifiers();
return this.parent.add(fieldDeclaration, bracketBalanceValue);
}
if (this.fields == null) {
this.fields= new RecoveredField[5];
this.fieldCount= 0;
} else {
if (this.fieldCount == this.fields.length) {
System.arraycopy(
this.fields,
0,
(this.fields= new RecoveredField[2 * this.fieldCount]),
0,
this.fieldCount);
}
}
RecoveredField element;
switch (fieldDeclaration.getKind()) {
case AbstractVariableDeclaration.FIELD:
case AbstractVariableDeclaration.ENUM_CONSTANT:
element= new RecoveredField(fieldDeclaration, this, bracketBalanceValue);
break;
case AbstractVariableDeclaration.INITIALIZER:
element= new RecoveredInitializer(fieldDeclaration, this, bracketBalanceValue);
break;
default:
// never happens, as field is always identified
return this;
}
this.fields[this.fieldCount++]= element;
if (this.pendingAnnotationCount > 0) {
element.attach(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
/* consider that if the opening brace was not found, it is there */
if (!this.foundOpeningBrace) {
this.foundOpeningBrace= true;
this.bracketBalance++;
}
/* if field not finished, then field becomes current */
if (fieldDeclaration.declarationSourceEnd == 0)
return element;
return this;
}
public RecoveredElement add(TypeDeclaration memberTypeDeclaration, int bracketBalanceValue) {
this.pendingTypeParameters= null;
/* do not consider a type starting passed the type end (if set)
it must be belonging to an enclosing type */
if (this.typeDeclaration.declarationSourceEnd != 0
&& memberTypeDeclaration.declarationSourceStart > this.typeDeclaration.declarationSourceEnd) {
resetPendingModifiers();
return this.parent.add(memberTypeDeclaration, bracketBalanceValue);
}
this.insideEnumConstantPart= false;
if ((memberTypeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
if (this.methodCount > 0) {
// add it to the last method body
RecoveredMethod lastMethod= this.methods[this.methodCount - 1];
lastMethod.methodDeclaration.bodyEnd= 0; // reopen method
lastMethod.methodDeclaration.declarationSourceEnd= 0; // reopen method
lastMethod.bracketBalance++; // expect one closing brace
resetPendingModifiers();
return lastMethod.add(memberTypeDeclaration, bracketBalanceValue);
} else {
// ignore
return this;
}
}
if (this.memberTypes == null) {
this.memberTypes= new RecoveredType[5];
this.memberTypeCount= 0;
} else {
if (this.memberTypeCount == this.memberTypes.length) {
System.arraycopy(
this.memberTypes,
0,
(this.memberTypes= new RecoveredType[2 * this.memberTypeCount]),
0,
this.memberTypeCount);
}
}
RecoveredType element= new RecoveredType(memberTypeDeclaration, this, bracketBalanceValue);
this.memberTypes[this.memberTypeCount++]= element;
if (this.pendingAnnotationCount > 0) {
element.attach(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
/* consider that if the opening brace was not found, it is there */
if (!this.foundOpeningBrace) {
this.foundOpeningBrace= true;
this.bracketBalance++;
}
/* if member type not finished, then member type becomes current */
if (memberTypeDeclaration.declarationSourceEnd == 0)
return element;
return this;
}
public void add(TypeParameter[] parameters, int startPos) {
this.pendingTypeParameters= parameters;
this.pendingTypeParametersStart= startPos;
}
public RecoveredElement addAnnotationName(int identifierPtr, int identifierLengthPtr, int annotationStart, int bracketBalanceValue) {
if (this.pendingAnnotations == null) {
this.pendingAnnotations= new RecoveredAnnotation[5];
this.pendingAnnotationCount= 0;
} else {
if (this.pendingAnnotationCount == this.pendingAnnotations.length) {
System.arraycopy(
this.pendingAnnotations,
0,
(this.pendingAnnotations= new RecoveredAnnotation[2 * this.pendingAnnotationCount]),
0,
this.pendingAnnotationCount);
}
}
RecoveredAnnotation element= new RecoveredAnnotation(identifierPtr, identifierLengthPtr, annotationStart, this, bracketBalanceValue);
this.pendingAnnotations[this.pendingAnnotationCount++]= element;
return element;
}
public void addModifier(int flag, int modifiersSourceStart) {
this.pendingModifiers|= flag;
if (this.pendingModifersSourceStart < 0) {
this.pendingModifersSourceStart= modifiersSourceStart;
}
}
public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) {
if (annotCount > 0) {
Annotation[] existingAnnotations= this.typeDeclaration.annotations;
if (existingAnnotations != null) {
this.annotations= new RecoveredAnnotation[annotCount];
this.annotationCount= 0;
next: for (int i= 0; i < annotCount; i++) {
for (int j= 0; j < existingAnnotations.length; j++) {
if (annots[i].annotation == existingAnnotations[j])
continue next;
}
this.annotations[this.annotationCount++]= annots[i];
}
} else {
this.annotations= annots;
this.annotationCount= annotCount;
}
}
if (mods != 0) {
this.modifiers= mods;
this.modifiersStart= modsSourceStart;
}
}
/*
* Answer the body end of the corresponding parse node
*/
public int bodyEnd() {
if (this.bodyEnd == 0)
return this.typeDeclaration.declarationSourceEnd;
return this.bodyEnd;
}
public boolean bodyStartsAtHeaderEnd() {
if (this.typeDeclaration.superInterfaces == null) {
if (this.typeDeclaration.superclass == null) {
if (this.typeDeclaration.typeParameters == null) {
return this.typeDeclaration.bodyStart == this.typeDeclaration.sourceEnd + 1;
} else {
return this.typeDeclaration.bodyStart == this.typeDeclaration.typeParameters[this.typeDeclaration.typeParameters.length - 1].sourceEnd + 1;
}
} else {
return this.typeDeclaration.bodyStart == this.typeDeclaration.superclass.sourceEnd + 1;
}
} else {
return this.typeDeclaration.bodyStart == this.typeDeclaration.superInterfaces[this.typeDeclaration.superInterfaces.length - 1].sourceEnd + 1;
}
}
/*
* Answer the enclosing type node, or null if none
*/
public RecoveredType enclosingType() {
RecoveredElement current= this.parent;
while (current != null) {
if (current instanceof RecoveredType) {
return (RecoveredType)current;
}
current= current.parent;
}
return null;
}
public int lastMemberEnd() {
int lastMemberEnd= this.typeDeclaration.bodyStart;
if (this.fieldCount > 0) {
FieldDeclaration lastField= this.fields[this.fieldCount - 1].fieldDeclaration;
if (lastMemberEnd < lastField.declarationSourceEnd && lastField.declarationSourceEnd != 0) {
lastMemberEnd= lastField.declarationSourceEnd;
}
}
if (this.methodCount > 0) {
AbstractMethodDeclaration lastMethod= this.methods[this.methodCount - 1].methodDeclaration;
if (lastMemberEnd < lastMethod.declarationSourceEnd && lastMethod.declarationSourceEnd != 0) {
lastMemberEnd= lastMethod.declarationSourceEnd;
}
}
if (this.memberTypeCount > 0) {
TypeDeclaration lastType= this.memberTypes[this.memberTypeCount - 1].typeDeclaration;
if (lastMemberEnd < lastType.declarationSourceEnd && lastType.declarationSourceEnd != 0) {
lastMemberEnd= lastType.declarationSourceEnd;
}
}
return lastMemberEnd;
}
public char[] name() {
return this.typeDeclaration.name;
}
/*
* Answer the associated parsed structure
*/
public ASTNode parseTree() {
return this.typeDeclaration;
}
public void resetPendingModifiers() {
this.pendingAnnotations= null;
this.pendingAnnotationCount= 0;
this.pendingModifiers= 0;
this.pendingModifersSourceStart= -1;
}
/*
* Answer the very source end of the corresponding parse node
*/
public int sourceEnd() {
return this.typeDeclaration.declarationSourceEnd;
}
public String toString(int tab) {
StringBuffer result= new StringBuffer(tabString(tab));
result.append("Recovered type:\n"); //$NON-NLS-1$
if ((this.typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
result.append(tabString(tab));
result.append(" "); //$NON-NLS-1$
}
this.typeDeclaration.print(tab + 1, result);
if (this.annotations != null) {
for (int i= 0; i < this.annotationCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.annotations[i].toString(tab + 1));
}
}
if (this.memberTypes != null) {
for (int i= 0; i < this.memberTypeCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.memberTypes[i].toString(tab + 1));
}
}
if (this.fields != null) {
for (int i= 0; i < this.fieldCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.fields[i].toString(tab + 1));
}
}
if (this.methods != null) {
for (int i= 0; i < this.methodCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.methods[i].toString(tab + 1));
}
}
return result.toString();
}
/*
* Update the bodyStart of the corresponding parse node
*/
public void updateBodyStart(int bodyStart) {
this.foundOpeningBrace= true;
this.typeDeclaration.bodyStart= bodyStart;
}
public Statement updatedStatement(int depth, Set knownTypes) {
// ignore closed anonymous type
if ((this.typeDeclaration.bits & ASTNode.IsAnonymousType) != 0 && !this.preserveContent) {
return null;
}
TypeDeclaration updatedType= updatedTypeDeclaration(depth + 1, knownTypes);
if (updatedType != null && (updatedType.bits & ASTNode.IsAnonymousType) != 0) {
/* in presence of an anonymous type, we want the full allocation expression */
QualifiedAllocationExpression allocation= updatedType.allocation;
if (allocation.statementEnd == -1) {
allocation.statementEnd= updatedType.declarationSourceEnd;
}
return allocation;
}
return updatedType;
}
public TypeDeclaration updatedTypeDeclaration(int depth, Set knownTypes) {
if (depth >= MAX_TYPE_DEPTH)
return null;
if (knownTypes.contains(this.typeDeclaration))
return null;
knownTypes.add(this.typeDeclaration);
int lastEnd= this.typeDeclaration.bodyStart;
/* update annotations */
if (this.modifiers != 0) {
this.typeDeclaration.modifiers|= this.modifiers;
if (this.modifiersStart < this.typeDeclaration.declarationSourceStart) {
this.typeDeclaration.declarationSourceStart= this.modifiersStart;
}
}
/* update annotations */
if (this.annotationCount > 0) {
int existingCount= this.typeDeclaration.annotations == null ? 0 : this.typeDeclaration.annotations.length;
Annotation[] annotationReferences= new Annotation[existingCount + this.annotationCount];
if (existingCount > 0) {
System.arraycopy(this.typeDeclaration.annotations, 0, annotationReferences, this.annotationCount, existingCount);
}
for (int i= 0; i < this.annotationCount; i++) {
annotationReferences[i]= this.annotations[i].updatedAnnotationReference();
}
this.typeDeclaration.annotations= annotationReferences;
int start= this.annotations[0].annotation.sourceStart;
if (start < this.typeDeclaration.declarationSourceStart) {
this.typeDeclaration.declarationSourceStart= start;
}
}
/* update member types */
if (this.memberTypeCount > 0) {
int existingCount= this.typeDeclaration.memberTypes == null ? 0 : this.typeDeclaration.memberTypes.length;
TypeDeclaration[] memberTypeDeclarations= new TypeDeclaration[existingCount + this.memberTypeCount];
if (existingCount > 0) {
System.arraycopy(this.typeDeclaration.memberTypes, 0, memberTypeDeclarations, 0, existingCount);
}
// may need to update the declarationSourceEnd of the last type
if (this.memberTypes[this.memberTypeCount - 1].typeDeclaration.declarationSourceEnd == 0) {
int bodyEndValue= bodyEnd();
this.memberTypes[this.memberTypeCount - 1].typeDeclaration.declarationSourceEnd= bodyEndValue;
this.memberTypes[this.memberTypeCount - 1].typeDeclaration.bodyEnd= bodyEndValue;
}
int updatedCount= 0;
for (int i= 0; i < this.memberTypeCount; i++) {
TypeDeclaration updatedTypeDeclaration= this.memberTypes[i].updatedTypeDeclaration(depth + 1, knownTypes);
if (updatedTypeDeclaration != null) {
memberTypeDeclarations[existingCount + (updatedCount++)]= updatedTypeDeclaration;
}
}
if (updatedCount < this.memberTypeCount) {
int length= existingCount + updatedCount;
System.arraycopy(memberTypeDeclarations, 0, memberTypeDeclarations= new TypeDeclaration[length], 0, length);
}
if (memberTypeDeclarations.length > 0) {
this.typeDeclaration.memberTypes= memberTypeDeclarations;
if (memberTypeDeclarations[memberTypeDeclarations.length - 1].declarationSourceEnd > lastEnd) {
lastEnd= memberTypeDeclarations[memberTypeDeclarations.length - 1].declarationSourceEnd;
}
}
}
/* update fields */
if (this.fieldCount > 0) {
int existingCount= this.typeDeclaration.fields == null ? 0 : this.typeDeclaration.fields.length;
FieldDeclaration[] fieldDeclarations= new FieldDeclaration[existingCount + this.fieldCount];
if (existingCount > 0) {
System.arraycopy(this.typeDeclaration.fields, 0, fieldDeclarations, 0, existingCount);
}
// may need to update the declarationSourceEnd of the last field
if (this.fields[this.fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0) {
int temp= bodyEnd();
this.fields[this.fieldCount - 1].fieldDeclaration.declarationSourceEnd= temp;
this.fields[this.fieldCount - 1].fieldDeclaration.declarationEnd= temp;
}
for (int i= 0; i < this.fieldCount; i++) {
fieldDeclarations[existingCount + i]= this.fields[i].updatedFieldDeclaration(depth, knownTypes);
}
for (int i= this.fieldCount - 1; 0 < i; i--) {
if (fieldDeclarations[existingCount + i - 1].declarationSourceStart == fieldDeclarations[existingCount + i].declarationSourceStart) {
fieldDeclarations[existingCount + i - 1].declarationSourceEnd= fieldDeclarations[existingCount + i].declarationSourceEnd;
fieldDeclarations[existingCount + i - 1].declarationEnd= fieldDeclarations[existingCount + i].declarationEnd;
}
}
this.typeDeclaration.fields= fieldDeclarations;
if (fieldDeclarations[fieldDeclarations.length - 1].declarationSourceEnd > lastEnd) {
lastEnd= fieldDeclarations[fieldDeclarations.length - 1].declarationSourceEnd;
}
}
/* update methods */
int existingCount= this.typeDeclaration.methods == null ? 0 : this.typeDeclaration.methods.length;
boolean hasConstructor= false, hasRecoveredConstructor= false;
boolean hasAbstractMethods= false;
int defaultConstructorIndex= -1;
if (this.methodCount > 0) {
AbstractMethodDeclaration[] methodDeclarations= new AbstractMethodDeclaration[existingCount + this.methodCount];
for (int i= 0; i < existingCount; i++) {
AbstractMethodDeclaration m= this.typeDeclaration.methods[i];
if (m.isDefaultConstructor())
defaultConstructorIndex= i;
if (m.isAbstract())
hasAbstractMethods= true;
methodDeclarations[i]= m;
}
// may need to update the declarationSourceEnd of the last method
if (this.methods[this.methodCount - 1].methodDeclaration.declarationSourceEnd == 0) {
int bodyEndValue= bodyEnd();
this.methods[this.methodCount - 1].methodDeclaration.declarationSourceEnd= bodyEndValue;
this.methods[this.methodCount - 1].methodDeclaration.bodyEnd= bodyEndValue;
}
for (int i= 0; i < this.methodCount; i++) {
AbstractMethodDeclaration updatedMethod= this.methods[i].updatedMethodDeclaration(depth, knownTypes);
if (updatedMethod.isConstructor())
hasRecoveredConstructor= true;
if (updatedMethod.isAbstract())
hasAbstractMethods= true;
methodDeclarations[existingCount + i]= updatedMethod;
}
this.typeDeclaration.methods= methodDeclarations;
if (methodDeclarations[methodDeclarations.length - 1].declarationSourceEnd > lastEnd) {
lastEnd= methodDeclarations[methodDeclarations.length - 1].declarationSourceEnd;
}
if (hasAbstractMethods)
this.typeDeclaration.bits|= ASTNode.HasAbstractMethods;
hasConstructor= this.typeDeclaration.checkConstructors(parser());
} else {
for (int i= 0; i < existingCount; i++) {
if (this.typeDeclaration.methods[i].isConstructor())
hasConstructor= true;
}
}
/* add clinit ? */
if (this.typeDeclaration.needClassInitMethod()) {
boolean alreadyHasClinit= false;
for (int i= 0; i < existingCount; i++) {
if (this.typeDeclaration.methods[i].isClinit()) {
alreadyHasClinit= true;
break;
}
}
if (!alreadyHasClinit)
this.typeDeclaration.addClinit();
}
/* add default constructor ? */
if (defaultConstructorIndex >= 0 && hasRecoveredConstructor) {
/* should discard previous default construtor */
AbstractMethodDeclaration[] methodDeclarations= new AbstractMethodDeclaration[this.typeDeclaration.methods.length - 1];
if (defaultConstructorIndex != 0) {
System.arraycopy(this.typeDeclaration.methods, 0, methodDeclarations, 0, defaultConstructorIndex);
}
if (defaultConstructorIndex != this.typeDeclaration.methods.length - 1) {
System.arraycopy(
this.typeDeclaration.methods,
defaultConstructorIndex + 1,
methodDeclarations,
defaultConstructorIndex,
this.typeDeclaration.methods.length - defaultConstructorIndex - 1);
}
this.typeDeclaration.methods= methodDeclarations;
} else {
int kind= TypeDeclaration.kind(this.typeDeclaration.modifiers);
if (!hasConstructor &&
kind != TypeDeclaration.INTERFACE_DECL &&
kind != TypeDeclaration.ANNOTATION_TYPE_DECL &&
this.typeDeclaration.allocation == null) {// if was already reduced, then constructor
boolean insideFieldInitializer= false;
RecoveredElement parentElement= this.parent;
while (parentElement != null) {
if (parentElement instanceof RecoveredField) {
insideFieldInitializer= true;
break;
}
parentElement= parentElement.parent;
}
this.typeDeclaration.createDefaultConstructor(!parser().diet || insideFieldInitializer, true);
}
}
if (this.parent instanceof RecoveredType) {
this.typeDeclaration.bits|= ASTNode.IsMemberType;
} else if (this.parent instanceof RecoveredMethod) {
this.typeDeclaration.bits|= ASTNode.IsLocalType;
}
if (this.typeDeclaration.declarationSourceEnd == 0) {
this.typeDeclaration.declarationSourceEnd= lastEnd;
this.typeDeclaration.bodyEnd= lastEnd;
}
return this.typeDeclaration;
}
/*
* Update the corresponding parse node from parser state which
* is about to disappear because of restarting recovery
*/
public void updateFromParserState() {
// anymous type and enum constant doesn't need to be updated
if (bodyStartsAtHeaderEnd() && this.typeDeclaration.allocation == null) {
Parser parser= parser();
/* might want to recover implemented interfaces */
// protection for bugs 15142
if (parser.listLength > 0 && parser.astLengthPtr > 0) { // awaiting interface type references
int length= parser.astLengthStack[parser.astLengthPtr];
int astPtr= parser.astPtr - length;
boolean canConsume= astPtr >= 0;
if (canConsume) {
if ((!(parser.astStack[astPtr] instanceof TypeDeclaration))) {
canConsume= false;
}
for (int i= 1, max= length + 1; i < max; i++) {
if (!(parser.astStack[astPtr + i] instanceof TypeReference)) {
canConsume= false;
}
}
}
if (canConsume) {
parser.consumeClassHeaderImplements();
// will reset typeListLength to zero
// thus this check will only be performed on first errorCheck after class X implements Y,Z,
}
} else if (parser.listTypeParameterLength > 0) {
int length= parser.listTypeParameterLength;
int genericsPtr= parser.genericsPtr;
boolean canConsume= genericsPtr + 1 >= length && parser.astPtr > -1;
if (canConsume) {
if (!(parser.astStack[parser.astPtr] instanceof TypeDeclaration)) {
canConsume= false;
}
while (genericsPtr + 1 > length && !(parser.genericsStack[genericsPtr] instanceof TypeParameter)) {
genericsPtr--;
}
for (int i= 0; i < length; i++) {
if (!(parser.genericsStack[genericsPtr - i] instanceof TypeParameter)) {
canConsume= false;
}
}
}
if (canConsume) {
TypeDeclaration typeDecl= (TypeDeclaration)parser.astStack[parser.astPtr];
System.arraycopy(parser.genericsStack, genericsPtr - length + 1, typeDecl.typeParameters= new TypeParameter[length], 0, length);
typeDecl.bodyStart= typeDecl.typeParameters[length - 1].declarationSourceEnd + 1;
parser.listTypeParameterLength= 0;
parser.lastCheckPoint= typeDecl.bodyStart;
}
}
}
}
/*
* A closing brace got consumed, might have closed the current element,
* in which case both the currentElement is exited
*/
public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd) {
if ((--this.bracketBalance <= 0) && (this.parent != null)) {
this.updateSourceEndIfNecessary(braceStart, braceEnd);
this.bodyEnd= braceStart - 1;
return this.parent;
}
return this;
}
/*
* An opening brace got consumed, might be the expected opening one of the current element,
* in which case the bodyStart is updated.
*/
public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd) {
/* in case the opening brace is not close enough to the signature, ignore it */
if (this.bracketBalance == 0) {
/*
if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd)
!= parser.scanner.searchLineNumber(braceEnd)){
*/
Parser parser= parser();
switch (parser.lastIgnoredToken) {
case -1:
case TokenNameextends:
case TokenNameimplements:
case TokenNameGREATER:
case TokenNameRIGHT_SHIFT:
case TokenNameUNSIGNED_RIGHT_SHIFT:
if (parser.recoveredStaticInitializerStart == 0)
break;
//$FALL-THROUGH$
default:
this.foundOpeningBrace= true;
this.bracketBalance= 1; // pretend the brace was already there
}
}
// might be an initializer
if (this.bracketBalance == 1) {
Block block= new Block(0);
Parser parser= parser();
block.sourceStart= parser.scanner.startPosition;
Initializer init;
if (parser.recoveredStaticInitializerStart == 0) {
init= new Initializer(block, ClassFileConstants.AccDefault);
} else {
init= new Initializer(block, ClassFileConstants.AccStatic);
init.declarationSourceStart= parser.recoveredStaticInitializerStart;
}
init.bodyStart= parser.scanner.currentPosition;
return this.add(init, 1);
}
return super.updateOnOpeningBrace(braceStart, braceEnd);
}
public void updateParseTree() {
updatedTypeDeclaration(0, new HashSet());
}
/*
* Update the declarationSourceEnd of the corresponding parse node
*/
public void updateSourceEndIfNecessary(int start, int end) {
if (this.typeDeclaration.declarationSourceEnd == 0) {
this.bodyEnd= 0;
this.typeDeclaration.declarationSourceEnd= end;
this.typeDeclaration.bodyEnd= end;
}
}
}