1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.parser;
14 * Internal initializer structure for parsing recovery
16 import org.eclipse.jdt.core.compiler.*;
17 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
18 import org.eclipse.jdt.internal.compiler.ast.Block;
19 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
20 import org.eclipse.jdt.internal.compiler.ast.Initializer;
21 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
22 import org.eclipse.jdt.internal.compiler.ast.Statement;
23 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
24 import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
25 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
27 public class RecoveredInitializer extends RecoveredField implements CompilerModifiers, TerminalTokens, BaseTypes {
29 public RecoveredType[] localTypes;
30 public int localTypeCount;
32 public RecoveredBlock initializerBody;
34 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance){
35 this(fieldDeclaration, parent, bracketBalance, null);
37 public RecoveredInitializer(FieldDeclaration fieldDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
38 super(fieldDeclaration, parent, bracketBalance, parser);
39 this.foundOpeningBrace = true;
42 * Record a nested block declaration
44 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
46 /* default behavior is to delegate recording to parent if any,
47 do not consider elements passed the known end (if set)
48 it must be belonging to an enclosing element
50 if (fieldDeclaration.declarationSourceEnd > 0
51 && nestedBlockDeclaration.sourceStart > fieldDeclaration.declarationSourceEnd){
52 if (this.parent == null) return this; // ignore
53 return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
55 /* consider that if the opening brace was not found, it is there */
56 if (!foundOpeningBrace){
57 foundOpeningBrace = true;
58 this.bracketBalance++;
60 initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
61 if (nestedBlockDeclaration.sourceEnd == 0) return initializerBody;
65 * Record a field declaration (act like inside method body)
67 public RecoveredElement add(FieldDeclaration newFieldDeclaration, int bracketBalanceValue) {
69 /* local variables inside initializer can only be final and non void */
70 char[][] fieldTypeName;
71 if ((newFieldDeclaration.modifiers & ~AccFinal) != 0 /* local var can only be final */
72 || (newFieldDeclaration.type == null) // initializer
73 || ((fieldTypeName = newFieldDeclaration.type.getTypeName()).length == 1 // non void
74 && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){
75 if (this.parent == null) return this; // ignore
76 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(newFieldDeclaration.declarationSourceStart - 1));
77 return this.parent.add(newFieldDeclaration, bracketBalanceValue);
80 /* default behavior is to delegate recording to parent if any,
81 do not consider elements passed the known end (if set)
82 it must be belonging to an enclosing element
84 if (this.fieldDeclaration.declarationSourceEnd > 0
85 && newFieldDeclaration.declarationSourceStart > this.fieldDeclaration.declarationSourceEnd){
86 if (this.parent == null) return this; // ignore
87 return this.parent.add(newFieldDeclaration, bracketBalanceValue);
89 // still inside initializer, treat as local variable
90 return this; // ignore
93 * Record a local declaration - regular method should have been created a block body
95 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
97 /* do not consider a type starting passed the type end (if set)
98 it must be belonging to an enclosing type */
99 if (fieldDeclaration.declarationSourceEnd != 0
100 && localDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
101 if (parent == null) return this; // ignore
102 return this.parent.add(localDeclaration, bracketBalanceValue);
104 /* method body should have been created */
105 Block block = new Block(0);
106 block.sourceStart = ((Initializer)fieldDeclaration).sourceStart;
107 RecoveredElement element = this.add(block, 1);
108 return element.add(localDeclaration, bracketBalanceValue);
111 * Record a statement - regular method should have been created a block body
113 public RecoveredElement add(Statement statement, int bracketBalanceValue) {
115 /* do not consider a statement starting passed the initializer end (if set)
116 it must be belonging to an enclosing type */
117 if (fieldDeclaration.declarationSourceEnd != 0
118 && statement.sourceStart > fieldDeclaration.declarationSourceEnd){
119 if (parent == null) return this; // ignore
120 return this.parent.add(statement, bracketBalanceValue);
122 /* initializer body should have been created */
123 Block block = new Block(0);
124 block.sourceStart = ((Initializer)fieldDeclaration).sourceStart;
125 RecoveredElement element = this.add(block, 1);
126 return element.add(statement, bracketBalanceValue);
128 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
130 /* do not consider a type starting passed the type end (if set)
131 it must be belonging to an enclosing type */
132 if (fieldDeclaration.declarationSourceEnd != 0
133 && typeDeclaration.declarationSourceStart > fieldDeclaration.declarationSourceEnd){
134 if (parent == null) return this; // ignore
135 return this.parent.add(typeDeclaration, bracketBalanceValue);
137 if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){
138 /* method body should have been created */
139 Block block = new Block(0);
140 block.sourceStart = ((Initializer)fieldDeclaration).sourceStart;
141 RecoveredElement element = this.add(block, 1);
142 return element.add(typeDeclaration, bracketBalanceValue);
144 if (localTypes == null) {
145 localTypes = new RecoveredType[5];
148 if (localTypeCount == localTypes.length) {
152 (localTypes = new RecoveredType[2 * localTypeCount]),
157 RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
158 localTypes[localTypeCount++] = element;
160 /* consider that if the opening brace was not found, it is there */
161 if (!foundOpeningBrace){
162 foundOpeningBrace = true;
163 this.bracketBalance++;
167 public String toString(int tab) {
168 StringBuffer result = new StringBuffer(tabString(tab));
169 result.append("Recovered initializer:\n"); //$NON-NLS-1$
170 this.fieldDeclaration.print(tab + 1, result);
171 if (this.initializerBody != null) {
172 result.append("\n"); //$NON-NLS-1$
173 result.append(this.initializerBody.toString(tab + 1));
175 return result.toString();
177 public FieldDeclaration updatedFieldDeclaration(){
179 if (initializerBody != null){
180 Block block = initializerBody.updatedBlock();
182 ((Initializer)fieldDeclaration).block = block;
184 if (this.localTypeCount > 0) fieldDeclaration.bits |= ASTNode.HasLocalTypeMASK;
187 if (fieldDeclaration.sourceEnd == 0){
188 fieldDeclaration.sourceEnd = fieldDeclaration.declarationSourceEnd;
190 return fieldDeclaration;
193 * A closing brace got consumed, might have closed the current element,
194 * in which case both the currentElement is exited
196 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
197 if ((--bracketBalance <= 0) && (parent != null)){
198 this.updateSourceEndIfNecessary(braceStart, braceEnd);
204 * An opening brace got consumed, might be the expected opening one of the current element,
205 * in which case the bodyStart is updated.
207 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
209 return this; // request to restart
212 * Update the declarationSourceEnd of the corresponding parse node
214 public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
215 if (this.fieldDeclaration.declarationSourceEnd == 0) {
216 Initializer initializer = (Initializer)fieldDeclaration;
217 if(parser().rBraceSuccessorStart >= braceEnd) {
218 if (initializer.bodyStart < parser().rBraceEnd) {
219 initializer.declarationSourceEnd = parser().rBraceEnd;
221 initializer.declarationSourceEnd = initializer.bodyStart;
223 if (initializer.bodyStart < parser().rBraceStart) {
224 initializer.bodyEnd = parser().rBraceStart;
226 initializer.bodyEnd = initializer.bodyStart;
229 initializer.declarationSourceEnd = braceEnd;
230 initializer.bodyEnd = braceStart - 1;
232 if(initializer.block != null) {
233 initializer.block.sourceEnd = initializer.declarationSourceEnd;