/******************************************************************************* * 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; /** * Internal field structure for parsing recovery */ 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.Block; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; 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.TypeDeclaration; 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; } }