removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / parser / RecoveredType.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.parser;
12
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.Block;
16 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
17 import org.eclipse.jdt.internal.compiler.ast.Initializer;
18 import org.eclipse.jdt.internal.compiler.ast.Statement;
19 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
20 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
21 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
22
23 /**
24  * Internal type structure for parsing recovery 
25  */
26
27 public class RecoveredType extends RecoveredStatement implements TerminalTokens, CompilerModifiers {
28         public TypeDeclaration typeDeclaration;
29
30         public RecoveredType[] memberTypes;
31         public int memberTypeCount;
32         public RecoveredField[] fields;
33         public int fieldCount;
34         public RecoveredMethod[] methods;
35         public int methodCount;
36
37         public boolean preserveContent = false; // only used for anonymous types
38         public int bodyEnd;
39         
40 public RecoveredType(TypeDeclaration typeDeclaration, RecoveredElement parent, int bracketBalance){
41         super(typeDeclaration, parent, bracketBalance);
42         this.typeDeclaration = typeDeclaration;
43         this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
44         if(this.foundOpeningBrace) {
45                 this.bracketBalance++;
46         }
47 }
48 public RecoveredElement add(AbstractMethodDeclaration methodDeclaration, int bracketBalanceValue) {
49
50         /* do not consider a method starting passed the type end (if set)
51                 it must be belonging to an enclosing type */
52         if (typeDeclaration.declarationSourceEnd != 0 
53                 && methodDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){
54                 return this.parent.add(methodDeclaration, bracketBalanceValue);
55         }
56
57         if (methods == null) {
58                 methods = new RecoveredMethod[5];
59                 methodCount = 0;
60         } else {
61                 if (methodCount == methods.length) {
62                         System.arraycopy(
63                                 methods, 
64                                 0, 
65                                 (methods = new RecoveredMethod[2 * methodCount]), 
66                                 0, 
67                                 methodCount); 
68                 }
69         }
70         RecoveredMethod element = new RecoveredMethod(methodDeclaration, this, bracketBalanceValue, this.recoveringParser);
71         methods[methodCount++] = element;
72
73         /* consider that if the opening brace was not found, it is there */
74         if (!foundOpeningBrace){
75                 foundOpeningBrace = true;
76                 this.bracketBalance++;
77         }
78         /* if method not finished, then method becomes current */
79         if (methodDeclaration.declarationSourceEnd == 0) return element;
80         return this;
81 }
82 public RecoveredElement add(Block nestedBlockDeclaration,int bracketBalanceValue) {
83         int modifiers = AccDefault;
84         if(this.parser().recoveredStaticInitializerStart != 0) {
85                 modifiers = AccStatic;
86         }
87         return this.add(new Initializer(nestedBlockDeclaration, modifiers), bracketBalanceValue);
88 }
89 public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
90         
91         /* do not consider a field starting passed the type end (if set)
92         it must be belonging to an enclosing type */
93         if (typeDeclaration.declarationSourceEnd != 0
94                 && fieldDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd) {
95                 return this.parent.add(fieldDeclaration, bracketBalanceValue);
96         }
97         if (fields == null) {
98                 fields = new RecoveredField[5];
99                 fieldCount = 0;
100         } else {
101                 if (fieldCount == fields.length) {
102                         System.arraycopy(
103                                 fields, 
104                                 0, 
105                                 (fields = new RecoveredField[2 * fieldCount]), 
106                                 0, 
107                                 fieldCount); 
108                 }
109         }
110         RecoveredField element = fieldDeclaration.isField() 
111                                                                 ? new RecoveredField(fieldDeclaration, this, bracketBalanceValue)
112                                                                 : new RecoveredInitializer(fieldDeclaration, this, bracketBalanceValue);
113         fields[fieldCount++] = element;
114
115         /* consider that if the opening brace was not found, it is there */
116         if (!foundOpeningBrace){
117                 foundOpeningBrace = true;
118                 this.bracketBalance++;
119         }
120         /* if field not finished, then field becomes current */
121         if (fieldDeclaration.declarationSourceEnd == 0) return element;
122         return this;
123 }
124 public RecoveredElement add(TypeDeclaration memberTypeDeclaration, int bracketBalanceValue) {
125
126         /* do not consider a type starting passed the type end (if set)
127                 it must be belonging to an enclosing type */
128         if (typeDeclaration.declarationSourceEnd != 0 
129                 && memberTypeDeclaration.declarationSourceStart > typeDeclaration.declarationSourceEnd){
130                 return this.parent.add(memberTypeDeclaration, bracketBalanceValue);
131         }
132         
133         if ((memberTypeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0){
134                 if (this.methodCount > 0) {
135                         // add it to the last method body
136                         RecoveredMethod lastMethod = this.methods[this.methodCount-1];
137                         lastMethod.methodDeclaration.bodyEnd = 0; // reopen method
138                         lastMethod.methodDeclaration.declarationSourceEnd = 0; // reopen method
139                         lastMethod.bracketBalance++; // expect one closing brace
140                         return lastMethod.add(memberTypeDeclaration, bracketBalanceValue);
141                 } else {
142                         // ignore
143                         return this;
144                 }
145         }       
146                 
147         if (memberTypes == null) {
148                 memberTypes = new RecoveredType[5];
149                 memberTypeCount = 0;
150         } else {
151                 if (memberTypeCount == memberTypes.length) {
152                         System.arraycopy(
153                                 memberTypes, 
154                                 0, 
155                                 (memberTypes = new RecoveredType[2 * memberTypeCount]), 
156                                 0, 
157                                 memberTypeCount); 
158                 }
159         }
160         RecoveredType element = new RecoveredType(memberTypeDeclaration, this, bracketBalanceValue);
161         memberTypes[memberTypeCount++] = element;
162
163         /* consider that if the opening brace was not found, it is there */
164         if (!foundOpeningBrace){
165                 foundOpeningBrace = true;
166                 this.bracketBalance++;
167         }
168         /* if member type not finished, then member type becomes current */
169         if (memberTypeDeclaration.declarationSourceEnd == 0) return element;
170         return this;
171 }
172 /*
173  * Answer the body end of the corresponding parse node
174  */
175 public int bodyEnd(){
176         if (bodyEnd == 0) return typeDeclaration.declarationSourceEnd;
177         return bodyEnd;
178 }
179 public boolean bodyStartsAtHeaderEnd(){
180         if (typeDeclaration.superInterfaces == null){
181                 if (typeDeclaration.superclass == null){
182                         return typeDeclaration.bodyStart == typeDeclaration.sourceEnd+1;
183                 } else {
184                         return typeDeclaration.bodyStart == typeDeclaration.superclass.sourceEnd+1;
185                 }
186         } else {
187                 return typeDeclaration.bodyStart 
188                                 == typeDeclaration.superInterfaces[typeDeclaration.superInterfaces.length-1].sourceEnd+1;
189         }
190 }
191 /*
192  * Answer the enclosing type node, or null if none
193  */
194 public RecoveredType enclosingType(){
195         RecoveredElement current = parent;
196         while (current != null){
197                 if (current instanceof RecoveredType){
198                         return (RecoveredType) current;
199                 }
200                 current = current.parent;
201         }
202         return null;
203 }
204 public char[] name(){
205         return typeDeclaration.name;
206 }
207 /* 
208  * Answer the associated parsed structure
209  */
210 public ASTNode parseTree(){
211         return typeDeclaration;
212 }
213 /*
214  * Answer the very source end of the corresponding parse node
215  */
216 public int sourceEnd(){
217         return this.typeDeclaration.declarationSourceEnd;
218 }
219 public String toString(int tab) {
220         StringBuffer result = new StringBuffer(tabString(tab));
221         result.append("Recovered type:\n"); //$NON-NLS-1$
222         if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
223                 result.append(tabString(tab));
224                 result.append(" "); //$NON-NLS-1$
225         }
226         typeDeclaration.print(tab + 1, result);
227         if (this.memberTypes != null) {
228                 for (int i = 0; i < this.memberTypeCount; i++) {
229                         result.append("\n"); //$NON-NLS-1$
230                         result.append(this.memberTypes[i].toString(tab + 1));
231                 }
232         }
233         if (this.fields != null) {
234                 for (int i = 0; i < this.fieldCount; i++) {
235                         result.append("\n"); //$NON-NLS-1$
236                         result.append(this.fields[i].toString(tab + 1));
237                 }
238         }
239         if (this.methods != null) {
240                 for (int i = 0; i < this.methodCount; i++) {
241                         result.append("\n"); //$NON-NLS-1$
242                         result.append(this.methods[i].toString(tab + 1));
243                 }
244         }
245         return result.toString();
246 }
247 /*
248  * Update the bodyStart of the corresponding parse node
249  */
250 public void updateBodyStart(int bodyStart){
251         this.foundOpeningBrace = true;
252         this.typeDeclaration.bodyStart = bodyStart;
253 }
254 public Statement updatedStatement(){
255
256         // ignore closed anonymous type
257         if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0 && !this.preserveContent){
258                 return null;
259         }
260                 
261         TypeDeclaration updatedType = this.updatedTypeDeclaration();
262         if ((updatedType.bits & ASTNode.IsAnonymousTypeMASK) != 0){
263                 /* in presence of an anonymous type, we want the full allocation expression */
264                 return updatedType.allocation;
265         }
266         return updatedType;
267 }
268 public TypeDeclaration updatedTypeDeclaration(){
269
270         /* update member types */
271         if (memberTypeCount > 0){
272                 int existingCount = typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length;
273                 TypeDeclaration[] memberTypeDeclarations = new TypeDeclaration[existingCount + memberTypeCount];
274                 if (existingCount > 0){
275                         System.arraycopy(typeDeclaration.memberTypes, 0, memberTypeDeclarations, 0, existingCount);
276                 }
277                 // may need to update the declarationSourceEnd of the last type
278                 if (memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd == 0){
279                         int bodyEndValue = bodyEnd();
280                         memberTypes[memberTypeCount - 1].typeDeclaration.declarationSourceEnd = bodyEndValue;
281                         memberTypes[memberTypeCount - 1].typeDeclaration.bodyEnd =  bodyEndValue;
282                 }
283                 for (int i = 0; i < memberTypeCount; i++){
284                         memberTypeDeclarations[existingCount + i] = memberTypes[i].updatedTypeDeclaration();
285                 }
286                 typeDeclaration.memberTypes = memberTypeDeclarations;
287         }
288         /* update fields */
289         if (fieldCount > 0){
290                 int existingCount = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length;
291                 FieldDeclaration[] fieldDeclarations = new FieldDeclaration[existingCount + fieldCount];
292                 if (existingCount > 0){
293                         System.arraycopy(typeDeclaration.fields, 0, fieldDeclarations, 0, existingCount);
294                 }
295                 // may need to update the declarationSourceEnd of the last field
296                 if (fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd == 0){
297                         int temp = bodyEnd();
298                         fields[fieldCount - 1].fieldDeclaration.declarationSourceEnd = temp;
299                         fields[fieldCount - 1].fieldDeclaration.declarationEnd = temp;
300                 }
301                 for (int i = 0; i < fieldCount; i++){
302                         fieldDeclarations[existingCount + i] = fields[i].updatedFieldDeclaration();
303                 }
304                 typeDeclaration.fields = fieldDeclarations;
305         }
306         /* update methods */
307         int existingCount = typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length;
308         boolean hasConstructor = false, hasRecoveredConstructor = false;
309         int defaultConstructorIndex = -1;
310         if (methodCount > 0){
311                 AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[existingCount + methodCount];
312                 for (int i = 0; i < existingCount; i++){
313                         AbstractMethodDeclaration m = typeDeclaration.methods[i];
314                         if (m.isDefaultConstructor()) defaultConstructorIndex = i;
315                         methodDeclarations[i] = m;
316                 }
317                 // may need to update the declarationSourceEnd of the last method
318                 if (methods[methodCount - 1].methodDeclaration.declarationSourceEnd == 0){
319                         int bodyEndValue = bodyEnd();
320                         methods[methodCount - 1].methodDeclaration.declarationSourceEnd = bodyEndValue;
321                         methods[methodCount - 1].methodDeclaration.bodyEnd = bodyEndValue;
322                 }
323                 for (int i = 0; i < methodCount; i++){
324                         AbstractMethodDeclaration updatedMethod = methods[i].updatedMethodDeclaration();                        
325                         if (updatedMethod.isConstructor()) hasRecoveredConstructor = true;
326                         methodDeclarations[existingCount + i] = updatedMethod;                  
327                 }
328                 typeDeclaration.methods = methodDeclarations;
329                 hasConstructor = typeDeclaration.checkConstructors(this.parser());
330         } else {
331                 for (int i = 0; i < existingCount; i++){
332                         if (typeDeclaration.methods[i].isConstructor()) hasConstructor = true;
333                 }               
334         }
335         /* add clinit ? */
336         if (typeDeclaration.needClassInitMethod()){
337                 boolean alreadyHasClinit = false;
338                 for (int i = 0; i < existingCount; i++){
339                         if (typeDeclaration.methods[i].isClinit()){
340                                 alreadyHasClinit = true;
341                                 break;
342                         }
343                 }
344                 if (!alreadyHasClinit) typeDeclaration.addClinit();
345         }
346         /* add default constructor ? */
347         if (defaultConstructorIndex >= 0 && hasRecoveredConstructor){
348                 /* should discard previous default construtor */
349                 AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[typeDeclaration.methods.length - 1];
350                 if (defaultConstructorIndex != 0){
351                         System.arraycopy(typeDeclaration.methods, 0, methodDeclarations, 0, defaultConstructorIndex);
352                 }
353                 if (defaultConstructorIndex != typeDeclaration.methods.length-1){
354                         System.arraycopy(
355                                 typeDeclaration.methods, 
356                                 defaultConstructorIndex+1, 
357                                 methodDeclarations, 
358                                 defaultConstructorIndex, 
359                                 typeDeclaration.methods.length - defaultConstructorIndex - 1);
360                 }
361                 typeDeclaration.methods = methodDeclarations;
362         } else {
363                 if (!hasConstructor && !typeDeclaration.isInterface()) {// if was already reduced, then constructor
364                         boolean insideFieldInitializer = false;
365                         RecoveredElement parentElement = this.parent; 
366                         while (parentElement != null){
367                                 if (parentElement instanceof RecoveredField){
368                                                 insideFieldInitializer = true;
369                                                 break; 
370                                 }
371                                 parentElement = parentElement.parent;
372                         }
373                         typeDeclaration.createsInternalConstructor(!parser().diet || insideFieldInitializer, true);
374                 } 
375         }
376         if (parent instanceof RecoveredType){
377                 typeDeclaration.bits |= ASTNode.IsMemberTypeMASK;
378         } else if (parent instanceof RecoveredMethod){
379                 typeDeclaration.bits |= ASTNode.IsLocalTypeMASK;
380         }
381         return typeDeclaration;
382 }
383 /*
384  * Update the corresponding parse node from parser state which
385  * is about to disappear because of restarting recovery
386  */
387 public void updateFromParserState(){
388
389         if(this.bodyStartsAtHeaderEnd()){
390                 Parser parser = this.parser();
391                 /* might want to recover implemented interfaces */
392                 // protection for bugs 15142
393                 if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
394                         int length = parser.astLengthStack[parser.astLengthPtr];
395                         int astPtr = parser.astPtr - length;
396                         boolean canConsume = astPtr >= 0;
397                         if(canConsume) {
398                                 if((!(parser.astStack[astPtr] instanceof TypeDeclaration))) {
399                                         canConsume = false;
400                                 }
401                                 for (int i = 1, max = length + 1; i < max; i++) {
402                                         if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
403                                                 canConsume = false;
404                                         }
405                                 }
406                         }
407                         if(canConsume) {
408                                 parser.consumeClassHeaderImplements(); 
409                                 // will reset typeListLength to zero
410                                 // thus this check will only be performed on first errorCheck after class X implements Y,Z,
411                         }
412                 }
413         }
414 }
415 /*
416  * A closing brace got consumed, might have closed the current element,
417  * in which case both the currentElement is exited
418  */
419 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
420         if ((--bracketBalance <= 0) && (parent != null)){
421                 this.updateSourceEndIfNecessary(braceStart, braceEnd);
422                 this.bodyEnd = braceStart - 1;
423                 return parent;
424         }
425         return this;
426 }
427 /*
428  * An opening brace got consumed, might be the expected opening one of the current element,
429  * in which case the bodyStart is updated.
430  */
431 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
432         /* in case the opening brace is not close enough to the signature, ignore it */
433         if (bracketBalance == 0){
434                 /*
435                         if (parser.scanner.searchLineNumber(typeDeclaration.sourceEnd) 
436                                 != parser.scanner.searchLineNumber(braceEnd)){
437                  */
438                 Parser parser = this.parser();
439                 switch(parser.lastIgnoredToken){
440                         case -1 :
441                         case TokenNameextends :
442                         case TokenNameimplements :
443                                 if (parser.recoveredStaticInitializerStart == 0) break;
444                         default:
445                                 this.foundOpeningBrace = true;                          
446                                 bracketBalance = 1; // pretend the brace was already there
447                 }
448         }       
449         // might be an initializer
450         if (this.bracketBalance == 1){
451                 Block block = new Block(0);
452                 Parser parser = this.parser();
453                 block.sourceStart = parser.scanner.startPosition;
454                 Initializer init;
455                 if (parser.recoveredStaticInitializerStart == 0){
456                         init = new Initializer(block, AccDefault);
457                 } else {
458                         init = new Initializer(block, AccStatic);
459                         init.declarationSourceStart = parser.recoveredStaticInitializerStart;
460                 }
461                 init.bodyStart = parser.scanner.currentPosition;
462                 return this.add(init, 1);
463         }
464         return super.updateOnOpeningBrace(braceStart, braceEnd);
465 }
466 public void updateParseTree(){
467         this.updatedTypeDeclaration();
468 }
469 /*
470  * Update the declarationSourceEnd of the corresponding parse node
471  */
472 public void updateSourceEndIfNecessary(int start, int end){
473         if (this.typeDeclaration.declarationSourceEnd == 0){
474                 this.bodyEnd = 0;
475                 this.typeDeclaration.declarationSourceEnd = end;
476                 this.typeDeclaration.bodyEnd = end;
477         }
478 }
479 }