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;
13 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
14 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
15 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
16 import org.eclipse.jdt.internal.compiler.ast.Block;
17 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
18 import org.eclipse.jdt.internal.compiler.ast.Initializer;
19 import org.eclipse.jdt.internal.compiler.ast.Statement;
20 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
21 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
22 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
23 import org.eclipse.jdt.internal.compiler.env.IGenericType;
24 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
27 * Internal type structure for parsing recovery
30 public class RecoveredType extends RecoveredStatement implements TerminalTokens, CompilerModifiers {
31 public TypeDeclaration typeDeclaration;
33 public RecoveredType[] memberTypes;
34 public int memberTypeCount;
35 public RecoveredField[] fields;
36 public int fieldCount;
37 public RecoveredMethod[] methods;
38 public int methodCount;
40 public boolean preserveContent = false; // only used for anonymous types
43 public boolean insideEnumConstantPart = false;
45 public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance){
46 super(typeDeclaration, parent, bracketBalance);
47 this.typeDeclaration = typeDeclaration;
48 this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
49 this.insideEnumConstantPart = typeDeclaration.kind() == IGenericType.ENUM_DECL;
50 if(this.foundOpeningBrace) {
51 this.bracketBalance++;
54 public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) {
56 /* do not consider a method starting passed the type end (if set)
57 it must be belonging to an enclosing type */
58 if (typeDeclaration.declarationSourceEnd != 0
59 && methodDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){
60 return this.parent.add(methodDeclaration, bracketBalanceValue);
63 if (methods == null) {
64 methods = new RecoveredMethod[5];
67 if (methodCount == methods.length) {
71 (methods = new RecoveredMethod[2 * methodCount]),
76 RecoveredMethod element = new RecoveredMethod(methodDeclaration, this, bracketBalanceValue, this.recoveringParser);
77 methods[methodCount++] = element;
79 this.insideEnumConstantPart = false;
81 /* consider that if the opening brace was not found, it is there */
82 if (!foundOpeningBrace){
83 foundOpeningBrace = true;
84 this.bracketBalance++;
86 /* if method not finished, then method becomes current */
87 if (methodDeclaration.declarationSourceEnd == 0) return element;
90 public RecoveredElement add(Block nestedBlockDeclaration,int bracketBalanceValue) {
91 int modifiers = AccDefault;
92 if(this.parser().recoveredStaticInitializerStart != 0) {
93 modifiers = AccStatic;
95 return this.add(new Initializer(nestedBlockDeclaration, modifiers), bracketBalanceValue);
97 public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
99 /* do not consider a field starting passed the type end (if set)
100 it must be belonging to an enclosing type */
101 if (typeDeclaration.declarationSourceEnd != 0
102 && fieldDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd) {
103 return this.parent.add(fieldDeclaration, bracketBalanceValue);
105 if (fields == null) {
106 fields = new RecoveredField[5];
109 if (fieldCount == fields.length) {
113 (fields = new RecoveredField[2 * fieldCount]),
118 RecoveredField element;
119 switch (fieldDeclaration.getKind()) {
120 case AbstractVariableDeclaration.FIELD:
121 case AbstractVariableDeclaration.ENUM_CONSTANT:
122 element = new RecoveredField(fieldDeclaration, this, bracketBalanceValue);
124 case AbstractVariableDeclaration.INITIALIZER:
125 element = new RecoveredInitializer(fieldDeclaration, this, bracketBalanceValue);
128 // never happens, as field is always identified
131 fields[fieldCount++] = element;
133 /* consider that if the opening brace was not found, it is there */
134 if (!foundOpeningBrace){
135 foundOpeningBrace = true;
136 this.bracketBalance++;
138 /* if field not finished, then field becomes current */
139 if (fieldDeclaration.declarationSourceEnd == 0) return element;
142 public RecoveredElement add(TypeDeclaration memberTypeDeclaration, int bracketBalanceValue) {
144 /* do not consider a type starting passed the type end (if set)
145 it must be belonging to an enclosing type */
146 if (typeDeclaration.declarationSourceEnd != 0
147 && memberTypeDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){
148 return this.parent.add(memberTypeDeclaration, bracketBalanceValue);
151 this.insideEnumConstantPart = false;
153 if ((memberTypeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0){
154 if (this.methodCount > 0) {
155 // add it to the last method body
156 RecoveredMethod lastMethod = this.methods[this.methodCount-1];
157 lastMethod.methodDeclaration.bodyEnd = 0; // reopen method
158 lastMethod.methodDeclaration.declarationSourceEnd = 0; // reopen method
159 lastMethod.bracketBalance++; // expect one closing brace
160 return lastMethod.add(memberTypeDeclaration, bracketBalanceValue);
167 if (memberTypes == null) {
168 memberTypes = new RecoveredType[5];
171 if (memberTypeCount == memberTypes.length) {
175 (memberTypes = new RecoveredType[2 * memberTypeCount]),
180 RecoveredType element = new RecoveredType(memberTypeDeclaration, this, bracketBalanceValue);
181 memberTypes[memberTypeCount++] = element;
183 /* consider that if the opening brace was not found, it is there */
184 if (!foundOpeningBrace){
185 foundOpeningBrace = true;
186 this.bracketBalance++;
188 /* if member type not finished, then member type becomes current */
189 if (memberTypeDeclaration.declarationSourceEnd == 0) return element;
193 * Answer the body end of the corresponding parse node
195 public int bodyEnd(){
196 if (bodyEnd == 0) return typeDeclaration.declarationSourceEnd;
199 public boolean bodyStartsAtHeaderEnd(){
200 if (typeDeclaration.superInterfaces == null){
201 if (typeDeclaration.superclass == null){
202 if(typeDeclaration.typeParameters == null) {
203 return typeDeclaration.bodyStart == typeDeclaration.sourceEnd+1;
205 return typeDeclaration.bodyStart == typeDeclaration.typeParameters[typeDeclaration.typeParameters.length-1].sourceEnd+1;
208 return typeDeclaration.bodyStart == typeDeclaration.superclass.sourceEnd+1;
211 return typeDeclaration.bodyStart
212 == typeDeclaration.superInterfaces[typeDeclaration.superInterfaces.length-1].sourceEnd+1;
216 * Answer the enclosing type node, or null if none
218 public RecoveredType enclosingType(){
219 RecoveredElement current = parent;
220 while (current != null){
221 if (current instanceof RecoveredType){
222 return (RecoveredType) current;
224 current = current.parent;
228 public char[] name(){
229 return typeDeclaration.name;
232 * Answer the associated parsed structure
234 public ASTNode parseTree(){
235 return typeDeclaration;
238 * Answer the very source end of the corresponding parse node
240 public int sourceEnd(){
241 return this.typeDeclaration.declarationSourceEnd;
243 public String toString(int tab) {
244 StringBuffer result = new StringBuffer(tabString(tab));
245 result.append("Recovered type:\n"); //$NON-NLS-1$
246 if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
247 result.append(tabString(tab));
248 result.append(" "); //$NON-NLS-1$
250 typeDeclaration.print(tab + 1, result);
251 if (this.memberTypes != null) {
252 for (int i = 0; i < this.memberTypeCount; i++) {
253 result.append("\n"); //$NON-NLS-1$
254 result.append(this.memberTypes[i].toString(tab + 1));
257 if (this.fields != null) {
258 for (int i = 0; i < this.fieldCount; i++) {
259 result.append("\n"); //$NON-NLS-1$
260 result.append(this.fields[i].toString(tab + 1));
263 if (this.methods != null) {
264 for (int i = 0; i < this.methodCount; i++) {
265 result.append("\n"); //$NON-NLS-1$
266 result.append(this.methods[i].toString(tab + 1));
269 return result.toString();
272 * Update the bodyStart of the corresponding parse node
274 public void updateBodyStart(int bodyStart){
275 this.foundOpeningBrace = true;
276 this.typeDeclaration.bodyStart = bodyStart;
278 public Statement updatedStatement(){
280 // ignore closed anonymous type
281 if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0 && !this.preserveContent){
285 TypeDeclaration updatedType = this.updatedTypeDeclaration();
286 if ((updatedType.bits & ASTNode.IsAnonymousTypeMASK) != 0){
287 /* in presence of an anonymous type, we want the full allocation expression */
288 return updatedType.allocation;
292 public TypeDeclaration updatedTypeDeclaration(){
294 /* update member types */
295 if (memberTypeCount > 0){
296 int existingCount = typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length;
297 TypeDeclaration[] memberTypeDeclarations = new TypeDeclaration[existingCount + memberTypeCount];
298 if (existingCount > 0){
299 System.arraycopy(typeDeclaration.memberTypes, 0, memberTypeDeclarations, 0, existingCount);
301 // may need to update the declarationSourceEnd of the last type
302 if (memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd == 0){
303 int bodyEndValue = bodyEnd();
304 memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd = bodyEndValue;
305 memberTypes[memberTypeCount - 1].typeDeclaration.bodyEnd = bodyEndValue;
307 for (int i = 0; i < memberTypeCount; i++){
308 memberTypeDeclarations[existingCount + i] = memberTypes[i].updatedTypeDeclaration();
310 typeDeclaration.memberTypes = memberTypeDeclarations;
314 int existingCount = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length;
315 FieldDeclaration[] fieldDeclarations = new FieldDeclaration[existingCount + fieldCount];
316 if (existingCount > 0){
317 System.arraycopy(typeDeclaration.fields, 0, fieldDeclarations, 0, existingCount);
319 // may need to update the declarationSourceEnd of the last field
320 if (fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0){
321 int temp = bodyEnd();
322 fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd = temp;
323 fields[fieldCount - 1].fieldDeclaration.declarationEnd = temp;
325 for (int i = 0; i < fieldCount; i++){
326 fieldDeclarations[existingCount + i] = fields[i].updatedFieldDeclaration();
328 typeDeclaration.fields = fieldDeclarations;
331 int existingCount = typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length;
332 boolean hasConstructor = false, hasRecoveredConstructor = false;
333 boolean hasAbstractMethods = false;
334 int defaultConstructorIndex = -1;
335 if (methodCount > 0){
336 AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[existingCount + methodCount];
337 for (int i = 0; i < existingCount; i++){
338 AbstractMethodDeclaration m = typeDeclaration.methods[i];
339 if (m.isDefaultConstructor()) defaultConstructorIndex = i;
340 if (m.isAbstract()) hasAbstractMethods = true;
341 methodDeclarations[i] = m;
343 // may need to update the declarationSourceEnd of the last method
344 if (methods[methodCount - 1].methodDeclaration.declarationSourceEnd == 0){
345 int bodyEndValue = bodyEnd();
346 methods[methodCount - 1].methodDeclaration.declarationSourceEnd = bodyEndValue;
347 methods[methodCount - 1].methodDeclaration.bodyEnd = bodyEndValue;
349 for (int i = 0; i < methodCount; i++){
350 AbstractMethodDeclaration updatedMethod = methods[i].updatedMethodDeclaration();
351 if (updatedMethod.isConstructor()) hasRecoveredConstructor = true;
352 if (updatedMethod.isAbstract()) hasAbstractMethods = true;
353 methodDeclarations[existingCount + i] = updatedMethod;
355 typeDeclaration.methods = methodDeclarations;
356 if (hasAbstractMethods) typeDeclaration.bits |= ASTNode.HasAbstractMethods;
357 hasConstructor = typeDeclaration.checkConstructors(this.parser());
359 for (int i = 0; i < existingCount; i++){
360 if (typeDeclaration.methods[i].isConstructor()) hasConstructor = true;
364 if (typeDeclaration.needClassInitMethod()){
365 boolean alreadyHasClinit = false;
366 for (int i = 0; i < existingCount; i++){
367 if (typeDeclaration.methods[i].isClinit()){
368 alreadyHasClinit = true;
372 if (!alreadyHasClinit) typeDeclaration.addClinit();
374 /* add default constructor ? */
375 if (defaultConstructorIndex >= 0 && hasRecoveredConstructor){
376 /* should discard previous default construtor */
377 AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[typeDeclaration.methods.length - 1];
378 if (defaultConstructorIndex != 0){
379 System.arraycopy(typeDeclaration.methods, 0, methodDeclarations, 0, defaultConstructorIndex);
381 if (defaultConstructorIndex != typeDeclaration.methods.length-1){
383 typeDeclaration.methods,
384 defaultConstructorIndex+1,
386 defaultConstructorIndex,
387 typeDeclaration.methods.length - defaultConstructorIndex - 1);
389 typeDeclaration.methods = methodDeclarations;
391 if (!hasConstructor && typeDeclaration.kind() != IGenericType.INTERFACE_DECL && typeDeclaration.kind() != IGenericType.ANNOTATION_TYPE_DECL) {// if was already reduced, then constructor
392 boolean insideFieldInitializer = false;
393 RecoveredElement parentElement = this.parent;
394 while (parentElement != null){
395 if (parentElement instanceof RecoveredField){
396 insideFieldInitializer = true;
399 parentElement = parentElement.parent;
401 typeDeclaration.createDefaultConstructor(!parser().diet || insideFieldInitializer, true);
404 if (parent instanceof RecoveredType){
405 typeDeclaration.bits |= ASTNode.IsMemberTypeMASK;
406 } else if (parent instanceof RecoveredMethod){
407 typeDeclaration.bits |= ASTNode.IsLocalTypeMASK;
409 return typeDeclaration;
412 * Update the corresponding parse node from parser state which
413 * is about to disappear because of restarting recovery
415 public void updateFromParserState(){
417 if(this.bodyStartsAtHeaderEnd()){
418 Parser parser = this.parser();
419 /* might want to recover implemented interfaces */
420 // protection for bugs 15142
421 if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
422 int length = parser.astLengthStack[parser.astLengthPtr];
423 int astPtr = parser.astPtr - length;
424 boolean canConsume = astPtr >= 0;
426 if((!(parser.astStack[astPtr] instanceof TypeDeclaration))) {
429 for (int i = 1, max = length + 1; i < max; i++) {
430 if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
436 parser.consumeClassHeaderImplements();
437 // will reset typeListLength to zero
438 // thus this check will only be performed on first errorCheck after class X implements Y,Z,
440 } else if (parser.listTypeParameterLength > 0) {
441 int length = parser.listTypeParameterLength;
442 int genericsPtr = parser.genericsPtr;
443 boolean canConsume = genericsPtr + 1 >= length && parser.astPtr > -1;
445 if (!(parser.astStack[parser.astPtr] instanceof TypeDeclaration)) {
448 while(genericsPtr + 1 > length && !(parser.genericsStack[genericsPtr] instanceof TypeParameter)) {
451 for (int i = 0; i < length; i++) {
452 if(!(parser.genericsStack[genericsPtr - i] instanceof TypeParameter)) {
458 TypeDeclaration typeDecl = (TypeDeclaration)parser.astStack[parser.astPtr];
459 System.arraycopy(parser.genericsStack, genericsPtr - length + 1, typeDecl.typeParameters = new TypeParameter[length], 0, length);
460 typeDecl.bodyStart = typeDecl.typeParameters[length-1].declarationSourceEnd + 1;
461 parser.listTypeParameterLength = 0;
462 parser.lastCheckPoint = typeDecl.bodyStart;
468 * A closing brace got consumed, might have closed the current element,
469 * in which case both the currentElement is exited
471 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
472 if ((--bracketBalance <= 0) && (parent != null)){
473 this.updateSourceEndIfNecessary(braceStart, braceEnd);
474 this.bodyEnd = braceStart - 1;
480 * An opening brace got consumed, might be the expected opening one of the current element,
481 * in which case the bodyStart is updated.
483 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
484 /* in case the opening brace is not close enough to the signature, ignore it */
485 if (bracketBalance == 0){
487 if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd)
488 != parser.scanner.searchLineNumber(braceEnd)){
490 Parser parser = this.parser();
491 switch(parser.lastIgnoredToken){
493 case TokenNameextends :
494 case TokenNameimplements :
495 case TokenNameGREATER :
496 case TokenNameRIGHT_SHIFT :
497 case TokenNameUNSIGNED_RIGHT_SHIFT :
498 if (parser.recoveredStaticInitializerStart == 0) break;
500 this.foundOpeningBrace = true;
501 bracketBalance = 1; // pretend the brace was already there
504 // might be an initializer
505 if (this.bracketBalance == 1){
506 Block block = new Block(0);
507 Parser parser = this.parser();
508 block.sourceStart = parser.scanner.startPosition;
510 if (parser.recoveredStaticInitializerStart == 0){
511 init = new Initializer(block, AccDefault);
513 init = new Initializer(block, AccStatic);
514 init.declarationSourceStart = parser.recoveredStaticInitializerStart;
516 init.bodyStart = parser.scanner.currentPosition;
517 return this.add(init, 1);
519 return super.updateOnOpeningBrace(braceStart, braceEnd);
521 public void updateParseTree(){
522 this.updatedTypeDeclaration();
525 * Update the declarationSourceEnd of the corresponding parse node
527 public void updateSourceEndIfNecessary(int start, int end){
528 if (this.typeDeclaration.declarationSourceEnd == 0){
530 this.typeDeclaration.declarationSourceEnd = end;
531 this.typeDeclaration.bodyEnd = end;