package org.eclipse.jdt.internal.compiler.parser; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
/** | |
* Internal field structure for parsing recovery | |
*/ | |
import org.eclipse.jdt.internal.compiler.ast.*; | |
public class RecoveredField extends RecoveredElement { | |
public FieldDeclaration fieldDeclaration; | |
boolean alreadyCompletedFieldInitialization; | |
public RecoveredType[] anonymousTypes; | |
public int anonymousTypeCount; | |
public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){ | |
this(fieldDeclaration, parent, bracketBalance, null); | |
} | |
public RecoveredField(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){ | |
super(parent, bracketBalance, parser); | |
this.fieldDeclaration = fieldDeclaration; | |
this.alreadyCompletedFieldInitialization = fieldDeclaration.initialization != null; | |
} | |
/* | |
* Record an expression statement if field is expecting an initialization expression, | |
* used for completion inside field initializers. | |
*/ | |
public RecoveredElement add(Statement statement, int bracketBalance) { | |
if (this.alreadyCompletedFieldInitialization || !(statement instanceof Expression)) { | |
return super.add(statement, bracketBalance); | |
} else { | |
this.alreadyCompletedFieldInitialization = true; | |
this.fieldDeclaration.initialization = (Expression)statement; | |
this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd; | |
return this; | |
} | |
} | |
/* | |
* Record a type declaration if this field is expecting an initialization expression | |
* and the type is an anonymous type. | |
* Used for completion inside field initializers. | |
*/ | |
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalance) { | |
if (this.alreadyCompletedFieldInitialization | |
|| !(typeDeclaration instanceof AnonymousLocalTypeDeclaration) | |
|| (this.fieldDeclaration.declarationSourceEnd != 0 && typeDeclaration.sourceStart > this.fieldDeclaration.declarationSourceEnd)) { | |
return super.add(typeDeclaration, bracketBalance); | |
} else { | |
// Prepare anonymous type list | |
if (this.anonymousTypes == null) { | |
this.anonymousTypes = new RecoveredType[5]; | |
this.anonymousTypeCount = 0; | |
} else { | |
if (this.anonymousTypeCount == this.anonymousTypes.length) { | |
System.arraycopy( | |
this.anonymousTypes, | |
0, | |
(this.anonymousTypes = new RecoveredType[2 * this.anonymousTypeCount]), | |
0, | |
this.anonymousTypeCount); | |
} | |
} | |
// Store type declaration as an anonymous type | |
RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalance); | |
this.anonymousTypes[this.anonymousTypeCount++] = element; | |
return element; | |
} | |
} | |
/* | |
* Answer the associated parsed structure | |
*/ | |
public AstNode parseTree(){ | |
return fieldDeclaration; | |
} | |
/* | |
* Answer the very source end of the corresponding parse node | |
*/ | |
public int sourceEnd(){ | |
return this.fieldDeclaration.declarationSourceEnd; | |
} | |
public String toString(int tab){ | |
StringBuffer buffer = new StringBuffer(tabString(tab)); | |
buffer.append("Recovered field:\n"); //$NON-NLS-1$ | |
buffer.append(fieldDeclaration.toString(tab + 1)); | |
if (this.anonymousTypes != null) { | |
for (int i = 0; i < this.anonymousTypeCount; i++){ | |
buffer.append("\n"); //$NON-NLS-1$ | |
buffer.append(anonymousTypes[i].toString(tab + 1)); | |
} | |
} | |
return buffer.toString(); | |
} | |
public FieldDeclaration updatedFieldDeclaration(){ | |
if (this.anonymousTypes != null && fieldDeclaration.initialization == null) { | |
for (int i = 0; i < this.anonymousTypeCount; i++){ | |
if (anonymousTypes[i].preserveContent){ | |
fieldDeclaration.initialization = | |
((AnonymousLocalTypeDeclaration)this.anonymousTypes[i].updatedTypeDeclaration()).allocation; | |
} | |
} | |
if (this.anonymousTypeCount > 0) fieldDeclaration.bits |= AstNode.HasLocalTypeMASK; | |
} | |
return fieldDeclaration; | |
} | |
/* | |
* A closing brace got consumed, might have closed the current element, | |
* in which case both the currentElement is exited. | |
* | |
* Fields have no associated braces, thus if matches, then update parent. | |
*/ | |
public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ | |
if (bracketBalance > 0){ // was an array initializer | |
bracketBalance--; | |
if (bracketBalance == 0) alreadyCompletedFieldInitialization = true; | |
return this; | |
} | |
if (parent != null){ | |
return parent.updateOnClosingBrace(braceStart, braceEnd); | |
} | |
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 currentPosition){ | |
if (fieldDeclaration.declarationSourceEnd == 0 | |
&& fieldDeclaration.type instanceof ArrayTypeReference | |
&& !alreadyCompletedFieldInitialization){ | |
bracketBalance++; | |
return null; // no update is necessary (array initializer) | |
} | |
// might be an array initializer | |
this.updateSourceEndIfNecessary(currentPosition - 1); | |
return this.parent.updateOnOpeningBrace(currentPosition); | |
} | |
public void updateParseTree(){ | |
this.updatedFieldDeclaration(); | |
} | |
/* | |
* Update the declarationSourceEnd of the corresponding parse node | |
*/ | |
public void updateSourceEndIfNecessary(int sourceEnd){ | |
if (this.fieldDeclaration.declarationSourceEnd == 0) | |
this.fieldDeclaration.declarationSourceEnd = sourceEnd; | |
} | |
} |