blob: fdc72b2c912f916d10839c59bfd54a8acf51ba28 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 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.Set;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
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.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
public class RecoveredInitializer extends RecoveredField implements TerminalTokens {
public RecoveredType[] localTypes;
public int localTypeCount;
public RecoveredBlock initializerBody;
int pendingModifiers;
int pendingModifersSourceStart = -1;
RecoveredAnnotation[] pendingAnnotations;
int pendingAnnotationCount;
public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){
this(fieldDeclaration, parent, bracketBalance, null);
}
public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
super(fieldDeclaration, parent, bracketBalance, parser);
this.foundOpeningBrace = true;
}
/*
* Record a nested block declaration
*/
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
/* default behavior is to delegate recording to parent if any,
do not consider elements passed the known end (if set)
it must be belonging to an enclosing element
*/
if (this.fieldDeclaration.declarationSourceEnd > 0
&& nestedBlockDeclaration.sourceStart > this.fieldDeclaration.declarationSourceEnd){
resetPendingModifiers();
if (this.parent == null) return this; // ignore
return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
}
/* consider that if the opening brace was not found, it is there */
if (!this.foundOpeningBrace){
this.foundOpeningBrace = true;
this.bracketBalance++;
}
if (this.initializerBody == null) {
return this.initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
}
if (nestedBlockDeclaration.sourceEnd == 0) return this.initializerBody;
return this.initializerBody.add(nestedBlockDeclaration, bracketBalanceValue, true);
}
/*
* Record a field declaration (act like inside method body)
*/
public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalanceValue) {
resetPendingModifiers();
/* local variables inside initializer can only be final and non void */
char[][] fieldTypeName;
if ((newFieldDeclaration.modifiers & ~ClassFileConstants.AccFinal) != 0 /* local var can only be final */
|| (newFieldDeclaration.type == null) // initializer
|| ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void
&& CharOperation.equals(fieldTypeName[0], TypeBinding.VOID.sourceName()))){
if (this.parent == null) return this; // ignore
this.updateSourceEndIfNecessary(previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1));
return this.parent.add(newFieldDeclaration, bracketBalanceValue);
}
/* default behavior is to delegate recording to parent if any,
do not consider elements passed the known end (if set)
it must be belonging to an enclosing element
*/
if (this.fieldDeclaration.declarationSourceEnd > 0
&& newFieldDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){
if (this.parent == null) return this; // ignore
return this.parent.add(newFieldDeclaration, bracketBalanceValue);
}
// still inside initializer, treat as local variable
return this; // ignore
}
/*
* Record a local declaration - regular method should have been created a block body
*/
public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
/* do not consider a type starting passed the type end (if set)
it must be belonging to an enclosing type */
if (this.fieldDeclaration.declarationSourceEnd != 0
&& localDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){
resetPendingModifiers();
if (this.parent == null) return this; // ignore
return this.parent.add(localDeclaration, bracketBalanceValue);
}
/* method body should have been created */
if (this.initializerBody == null) {
Block block = new Block(0);
block.sourceStart = ((Initializer)this.fieldDeclaration).sourceStart;
RecoveredElement element = this.add(block, 1);
if (this.bracketBalance > 0){
for (int i = 0; i < this.bracketBalance - 1; i++){
element = element.add(new Block(0), 1);
}
this.bracketBalance = 1;
}
return element.add(localDeclaration, bracketBalanceValue);
}
this.initializerBody.attachPendingModifiers(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
resetPendingModifiers();
return this.initializerBody.add(localDeclaration, bracketBalanceValue, true);
}
/*
* Record a statement - regular method should have been created a block body
*/
public RecoveredElement add(Statement statement, int bracketBalanceValue) {
/* do not consider a statement starting passed the initializer end (if set)
it must be belonging to an enclosing type */
if (this.fieldDeclaration.declarationSourceEnd != 0
&& statement.sourceStart > this.fieldDeclaration.declarationSourceEnd){
resetPendingModifiers();
if (this.parent == null) return this; // ignore
return this.parent.add(statement, bracketBalanceValue);
}
/* initializer body should have been created */
Block block = new Block(0);
block.sourceStart = ((Initializer)this.fieldDeclaration).sourceStart;
RecoveredElement element = this.add(block, 1);
if (this.initializerBody != null) {
this.initializerBody.attachPendingModifiers(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
return element.add(statement, bracketBalanceValue);
}
public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
/* do not consider a type starting passed the type end (if set)
it must be belonging to an enclosing type */
if (this.fieldDeclaration.declarationSourceEnd != 0
&& typeDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){
resetPendingModifiers();
if (this.parent == null) return this; // ignore
return this.parent.add(typeDeclaration, bracketBalanceValue);
}
if ((typeDeclaration.bits & ASTNode.IsLocalType) != 0 || parser().methodRecoveryActivated || parser().statementRecoveryActivated){
/* method body should have been created */
Block block = new Block(0);
block.sourceStart = ((Initializer)this.fieldDeclaration).sourceStart;
RecoveredElement element = this.add(block, 1);
if (this.initializerBody != null) {
this.initializerBody.attachPendingModifiers(
this.pendingAnnotations,
this.pendingAnnotationCount,
this.pendingModifiers,
this.pendingModifersSourceStart);
}
resetPendingModifiers();
return element.add(typeDeclaration, bracketBalanceValue);
}
if (this.localTypes == null) {
this.localTypes = new RecoveredType[5];
this.localTypeCount = 0;
} else {
if (this.localTypeCount == this.localTypes.length) {
System.arraycopy(
this.localTypes,
0,
(this.localTypes = new RecoveredType[2 * this.localTypeCount]),
0,
this.localTypeCount);
}
}
RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
this.localTypes[this.localTypeCount++] = 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++;
}
return element;
}
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 resetPendingModifiers() {
this.pendingAnnotations = null;
this.pendingAnnotationCount = 0;
this.pendingModifiers = 0;
this.pendingModifersSourceStart = -1;
}
public String toString(int tab) {
StringBuffer result = new StringBuffer(tabString(tab));
result.append("Recovered initializer:\n"); //$NON-NLS-1$
this.fieldDeclaration.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.initializerBody != null) {
result.append("\n"); //$NON-NLS-1$
result.append(this.initializerBody.toString(tab + 1));
}
return result.toString();
}
public FieldDeclaration updatedFieldDeclaration(int depth, Set<TypeDeclaration> knownTypes){
if (this.initializerBody != null){
Block block = this.initializerBody.updatedBlock(depth, knownTypes);
if (block != null){
Initializer initializer = (Initializer) this.fieldDeclaration;
initializer.block = block;
if (initializer.declarationSourceEnd == 0) {
initializer.declarationSourceEnd = block.sourceEnd;
initializer.bodyEnd = block.sourceEnd;
}
}
if (this.localTypeCount > 0) this.fieldDeclaration.bits |= ASTNode.HasLocalType;
}
if (this.fieldDeclaration.sourceEnd == 0){
this.fieldDeclaration.sourceEnd = this.fieldDeclaration.declarationSourceEnd;
}
return this.fieldDeclaration;
}
/*
* 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);
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){
this.bracketBalance++;
return this; // request to restart
}
/*
* Update the declarationSourceEnd of the corresponding parse node
*/
public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
if (this.fieldDeclaration.declarationSourceEnd == 0) {
Initializer initializer = (Initializer)this.fieldDeclaration;
if(parser().rBraceSuccessorStart >= braceEnd) {
if (initializer.bodyStart < parser().rBraceEnd) {
initializer.declarationSourceEnd = parser().rBraceEnd;
} else {
initializer.declarationSourceEnd = initializer.bodyStart;
}
if (initializer.bodyStart < parser().rBraceStart) {
initializer.bodyEnd = parser().rBraceStart;
} else {
initializer.bodyEnd = initializer.bodyStart;
}
} else {
if (braceEnd < initializer.declarationSourceStart) {
initializer.declarationSourceEnd = initializer.declarationSourceStart;
initializer.bodyEnd = initializer.declarationSourceEnd;
} else {
initializer.declarationSourceEnd = braceEnd;
initializer.bodyEnd = braceStart - 1;
}
if (initializer.bodyStart > initializer.declarationSourceEnd) {
initializer.bodyStart = initializer.declarationSourceEnd;
if(initializer.block != null) {
initializer.block.sourceStart = initializer.declarationSourceStart;
}
}
}
if(initializer.block != null) {
initializer.block.sourceEnd = initializer.declarationSourceEnd;
}
}
}
}