/*******************************************************************************
* 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.che.ide.ext.java.jdt.internal.compiler.parser;
/**
* Internal field structure for parsing recovery
*/
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.Block;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.Initializer;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.TypeDeclaration;
import java.util.HashSet;
import java.util.Set;
public class RecoveredUnit extends RecoveredElement {
public CompilationUnitDeclaration unitDeclaration;
public RecoveredImport[] imports;
public int importCount;
public RecoveredType[] types;
public int typeCount;
int pendingModifiers;
int pendingModifersSourceStart = -1;
RecoveredAnnotation[] pendingAnnotations;
int pendingAnnotationCount;
public RecoveredUnit(CompilationUnitDeclaration unitDeclaration, int bracketBalance, Parser parser) {
super(null, bracketBalance, parser);
this.unitDeclaration = unitDeclaration;
}
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;
}
}
/* Record a method declaration: should be attached to last type */
public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) {
/* attach it to last type - if any */
if (this.typeCount > 0) {
RecoveredType type = this.types[this.typeCount - 1];
int start = type.bodyEnd;
int end = type.typeDeclaration.bodyEnd;
type.bodyEnd = 0; // reset position
type.typeDeclaration.declarationSourceEnd = 0; // reset position
type.typeDeclaration.bodyEnd = 0;
int kind = TypeDeclaration.kind(type.typeDeclaration.modifiers);
if (start > 0 && start < end && kind != TypeDeclaration.INTERFACE_DECL
&& kind != TypeDeclaration.ANNOTATION_TYPE_DECL) {
// the } of the last type can be considered as the end of an initializer
Initializer initializer = new Initializer(new Block(0), 0);
initializer.bodyStart = end;
initializer.bodyEnd = end;
initializer.declarationSourceStart = end;
initializer.declarationSourceEnd = end;
initializer.sourceStart = end;
initializer.sourceEnd = end;
type.add(initializer, bracketBalanceValue);
}
resetPendingModifiers();
return type.add(methodDeclaration, bracketBalanceValue);
}
return this; // ignore
}
/* Record a field declaration: should be attached to last type */
public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
/* attach it to last type - if any */
if (this.typeCount > 0) {
RecoveredType type = this.types[this.typeCount - 1];
type.bodyEnd = 0; // reset position
type.typeDeclaration.declarationSourceEnd = 0; // reset position
type.typeDeclaration.bodyEnd = 0;
resetPendingModifiers();
return type.add(fieldDeclaration, bracketBalanceValue);
}
return this; // ignore
}
public RecoveredElement add(ImportReference importReference, int bracketBalanceValue) {
resetPendingModifiers();
if (this.imports == null) {
this.imports = new RecoveredImport[5];
this.importCount = 0;
} else {
if (this.importCount == this.imports.length) {
System.arraycopy(this.imports, 0, (this.imports = new RecoveredImport[2 * this.importCount]), 0,
this.importCount);
}
}
RecoveredImport element = new RecoveredImport(importReference, this, bracketBalanceValue);
this.imports[this.importCount++] = element;
/* if import not finished, then import becomes current */
if (importReference.declarationSourceEnd == 0)
return element;
return this;
}
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
if (this.typeCount > 0) {
// add it to the last type
RecoveredType lastType = this.types[this.typeCount - 1];
lastType.bodyEnd = 0; // reopen type
lastType.typeDeclaration.bodyEnd = 0; // reopen type
lastType.typeDeclaration.declarationSourceEnd = 0; // reopen type
lastType.bracketBalance++; // expect one closing brace
resetPendingModifiers();
return lastType.add(typeDeclaration, bracketBalanceValue);
}
}
if (this.types == null) {
this.types = new RecoveredType[5];
this.typeCount = 0;
} else {
if (this.typeCount == this.types.length) {
System.arraycopy(this.types, 0, (this.types = new RecoveredType[2 * this.typeCount]), 0, this.typeCount);
}
}
RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
this.types[this.typeCount++] = element;
if (this.pendingAnnotationCount > 0) {
element.attach(this.pendingAnnotations, this.pendingAnnotationCount, this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
/* if type not finished, then type becomes current */
if (typeDeclaration.declarationSourceEnd == 0)
return element;
return this;
}
/* Answer the associated parsed structure */
public ASTNode parseTree() {
return this.unitDeclaration;
}
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.unitDeclaration.sourceEnd;
}
public String toString(int tab) {
StringBuffer result = new StringBuffer(tabString(tab));
result.append("Recovered unit: [\n"); //$NON-NLS-1$
this.unitDeclaration.print(tab + 1, result);
result.append(tabString(tab + 1));
result.append("]"); //$NON-NLS-1$
if (this.imports != null) {
for (int i = 0; i < this.importCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.imports[i].toString(tab + 1));
}
}
if (this.types != null) {
for (int i = 0; i < this.typeCount; i++) {
result.append("\n"); //$NON-NLS-1$
result.append(this.types[i].toString(tab + 1));
}
}
return result.toString();
}
public CompilationUnitDeclaration updatedCompilationUnitDeclaration() {
/* update imports */
if (this.importCount > 0) {
ImportReference[] importRefences = new ImportReference[this.importCount];
for (int i = 0; i < this.importCount; i++) {
importRefences[i] = this.imports[i].updatedImportReference();
}
this.unitDeclaration.imports = importRefences;
}
/* update types */
if (this.typeCount > 0) {
int existingCount = this.unitDeclaration.types == null ? 0 : this.unitDeclaration.types.length;
TypeDeclaration[] typeDeclarations = new TypeDeclaration[existingCount + this.typeCount];
if (existingCount > 0) {
System.arraycopy(this.unitDeclaration.types, 0, typeDeclarations, 0, existingCount);
}
// may need to update the declarationSourceEnd of the last type
if (this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd == 0) {
this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd = this.unitDeclaration.sourceEnd;
this.types[this.typeCount - 1].typeDeclaration.bodyEnd = this.unitDeclaration.sourceEnd;
}
Set knownTypes = new HashSet();
int actualCount = existingCount;
for (int i = 0; i < this.typeCount; i++) {
TypeDeclaration typeDecl = this.types[i].updatedTypeDeclaration(0, knownTypes);
// filter out local types (12454)
if (typeDecl != null && (typeDecl.bits & ASTNode.IsLocalType) == 0) {
typeDeclarations[actualCount++] = typeDecl;
}
}
if (actualCount != this.typeCount) {
System.arraycopy(typeDeclarations, 0, typeDeclarations = new TypeDeclaration[existingCount + actualCount],
0, existingCount + actualCount);
}
this.unitDeclaration.types = typeDeclarations;
}
return this.unitDeclaration;
}
public void updateParseTree() {
updatedCompilationUnitDeclaration();
}
/* Update the sourceEnd of the corresponding parse node */
public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd) {
if (this.unitDeclaration.sourceEnd == 0)
this.unitDeclaration.sourceEnd = bodyEnd;
}
}