Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / parser / RecoveredMethod.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.core.compiler.*;
14 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import org.eclipse.jdt.internal.compiler.ast.Argument;
16 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
17 import org.eclipse.jdt.internal.compiler.ast.Block;
18 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
19 import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
20 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
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.SuperReference;
24 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
25 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
26 import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
27 import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
28
29 /**
30  * Internal method structure for parsing recovery 
31  */
32
33 public class RecoveredMethod extends RecoveredElement implements CompilerModifiers, TerminalTokens, BaseTypes {
34
35         public AbstractMethodDeclaration methodDeclaration;
36
37         public RecoveredType[] localTypes;
38         public int localTypeCount;
39
40         public RecoveredBlock methodBody;
41         public boolean discardBody = true;
42
43 public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
44         super(parent, bracketBalance, parser);
45         this.methodDeclaration = methodDeclaration;
46         this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
47         if(this.foundOpeningBrace) {
48                 this.bracketBalance++;
49         }
50 }
51 /*
52  * Record a nested block declaration
53  */
54 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
55
56         /* default behavior is to delegate recording to parent if any,
57         do not consider elements passed the known end (if set)
58         it must be belonging to an enclosing element 
59         */
60         if (methodDeclaration.declarationSourceEnd > 0
61                 && nestedBlockDeclaration.sourceStart
62                         > methodDeclaration.declarationSourceEnd){
63                                 if (this.parent == null){
64                                         return this; // ignore
65                                 } else {
66                                         return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
67                                 }
68         }
69         /* consider that if the opening brace was not found, it is there */
70         if (!foundOpeningBrace){
71                 foundOpeningBrace = true;
72                 this.bracketBalance++;
73         }
74
75         methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
76         if (nestedBlockDeclaration.sourceEnd == 0) return methodBody;
77         return this;
78 }
79 /*
80  * Record a field declaration
81  */
82 public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
83
84         /* local variables inside method can only be final and non void */
85         char[][] fieldTypeName; 
86         if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
87                 || (fieldDeclaration.type == null) // initializer
88                 || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void
89                         && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ 
90
91                 if (this.parent == null){
92                         return this; // ignore
93                 } else {
94                         this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
95                         return this.parent.add(fieldDeclaration, bracketBalanceValue);
96                 }
97         }
98         /* default behavior is to delegate recording to parent if any,
99         do not consider elements passed the known end (if set)
100         it must be belonging to an enclosing element 
101         */
102         if (methodDeclaration.declarationSourceEnd > 0
103                 && fieldDeclaration.declarationSourceStart
104                         > methodDeclaration.declarationSourceEnd){
105                 if (this.parent == null){
106                         return this; // ignore
107                 } else {
108                         return this.parent.add(fieldDeclaration, bracketBalanceValue);
109                 }
110         }
111         /* consider that if the opening brace was not found, it is there */
112         if (!foundOpeningBrace){
113                 foundOpeningBrace = true;
114                 this.bracketBalance++;
115         }
116         // still inside method, treat as local variable
117         return this; // ignore
118 }
119 /*
120  * Record a local declaration - regular method should have been created a block body
121  */
122 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
123
124         /* local variables inside method can only be final and non void */
125 /*      
126         char[][] localTypeName; 
127         if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
128                 || (localDeclaration.type == null) // initializer
129                 || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void
130                         && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ 
131
132                 if (this.parent == null){
133                         return this; // ignore
134                 } else {
135                         this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
136                         return this.parent.add(localDeclaration, bracketBalance);
137                 }
138         }
139 */
140         /* do not consider a type starting passed the type end (if set)
141                 it must be belonging to an enclosing type */
142         if (methodDeclaration.declarationSourceEnd != 0 
143                 && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
144                         
145                 if (this.parent == null) {
146                         return this; // ignore
147                 } else {
148                         return this.parent.add(localDeclaration, bracketBalanceValue);
149                 }
150         }
151         if (methodBody == null){
152                 Block block = new Block(0);
153                 block.sourceStart = methodDeclaration.bodyStart;
154                 RecoveredElement currentBlock = this.add(block, 1);
155                 if (this.bracketBalance > 0){
156                         for (int i = 0; i < this.bracketBalance - 1; i++){
157                                 currentBlock = currentBlock.add(new Block(0), 1);
158                         }
159                         this.bracketBalance = 1;
160                 }
161                 return currentBlock.add(localDeclaration, bracketBalanceValue);
162         }
163         return methodBody.add(localDeclaration, bracketBalanceValue, true);
164 }
165 /*
166  * Record a statement - regular method should have been created a block body
167  */
168 public RecoveredElement add(Statement statement, int bracketBalanceValue) {
169
170         /* do not consider a type starting passed the type end (if set)
171                 it must be belonging to an enclosing type */
172         if (methodDeclaration.declarationSourceEnd != 0 
173                 && statement.sourceStart > methodDeclaration.declarationSourceEnd){
174
175                 if (this.parent == null) {
176                         return this; // ignore
177                 } else {
178                         return this.parent.add(statement, bracketBalanceValue);
179                 }
180         }
181         if (methodBody == null){
182                 Block block = new Block(0);
183                 block.sourceStart = methodDeclaration.bodyStart;
184                 RecoveredElement currentBlock = this.add(block, 1);
185                 if (this.bracketBalance > 0){
186                         for (int i = 0; i < this.bracketBalance - 1; i++){
187                                 currentBlock = currentBlock.add(new Block(0), 1);
188                         }
189                         this.bracketBalance = 1;
190                 }
191                 return currentBlock.add(statement, bracketBalanceValue);
192         }
193         return methodBody.add(statement, bracketBalanceValue, true);    
194 }
195 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
196
197         /* do not consider a type starting passed the type end (if set)
198                 it must be belonging to an enclosing type */
199         if (methodDeclaration.declarationSourceEnd != 0 
200                 && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
201                         
202                 if (this.parent == null) {
203                         return this; // ignore
204                 }
205                 return this.parent.add(typeDeclaration, bracketBalanceValue);
206         }
207         if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){
208                 if (methodBody == null){
209                         Block block = new Block(0);
210                         block.sourceStart = methodDeclaration.bodyStart;
211                         this.add(block, 1);
212                 }
213                 return methodBody.add(typeDeclaration, bracketBalanceValue, true);      
214         }
215         if (typeDeclaration.isInterface()) {
216                 this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
217                 if (this.parent == null) {
218                         return this; // ignore
219                 }
220                 // close the constructor
221                 return this.parent.add(typeDeclaration, bracketBalanceValue);
222         }
223         if (localTypes == null) {
224                 localTypes = new RecoveredType[5];
225                 localTypeCount = 0;
226         } else {
227                 if (localTypeCount == localTypes.length) {
228                         System.arraycopy(
229                                 localTypes, 
230                                 0, 
231                                 (localTypes = new RecoveredType[2 * localTypeCount]), 
232                                 0, 
233                                 localTypeCount); 
234                 }
235         }
236         RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
237         localTypes[localTypeCount++] = element;
238
239         /* consider that if the opening brace was not found, it is there */
240         if (!foundOpeningBrace){
241                 foundOpeningBrace = true;
242                 this.bracketBalance++;
243         }
244         return element;
245 }
246 public boolean bodyStartsAtHeaderEnd(){
247         return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1;
248 }
249 /* 
250  * Answer the associated parsed structure
251  */
252 public ASTNode parseTree(){
253         return methodDeclaration;
254 }
255 /*
256  * Answer the very source end of the corresponding parse node
257  */
258 public int sourceEnd(){
259         return this.methodDeclaration.declarationSourceEnd;
260 }
261 public String toString(int tab) {
262         StringBuffer result = new StringBuffer(tabString(tab));
263         result.append("Recovered method:\n"); //$NON-NLS-1$
264         this.methodDeclaration.print(tab + 1, result);
265         if (this.localTypes != null) {
266                 for (int i = 0; i < this.localTypeCount; i++) {
267                         result.append("\n"); //$NON-NLS-1$
268                         result.append(this.localTypes[i].toString(tab + 1));
269                 }
270         }
271         if (this.methodBody != null) {
272                 result.append("\n"); //$NON-NLS-1$
273                 result.append(this.methodBody.toString(tab + 1));
274         }
275         return result.toString();
276 }
277 /*
278  * Update the bodyStart of the corresponding parse node
279  */
280 public void updateBodyStart(int bodyStart){
281         this.foundOpeningBrace = true;          
282         this.methodDeclaration.bodyStart = bodyStart;
283 }
284 public AbstractMethodDeclaration updatedMethodDeclaration(){
285
286         if (methodBody != null){
287                 Block block = methodBody.updatedBlock();
288                 if (block != null){
289                         methodDeclaration.statements = block.statements;
290
291                         /* first statement might be an explict constructor call destinated to a special slot */
292                         if (methodDeclaration.isConstructor()) {
293                                 ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration;
294                                 if (methodDeclaration.statements != null
295                                         && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){
296                                         constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0];
297                                         int length = methodDeclaration.statements.length;
298                                         System.arraycopy(
299                                                 methodDeclaration.statements, 
300                                                 1, 
301                                                 (methodDeclaration.statements = new Statement[length-1]),
302                                                 0,
303                                                 length-1);
304                                         }
305                                         if (constructor.constructorCall == null){ // add implicit constructor call
306                                                 constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
307                                         }
308                         }
309                 }
310         }
311         if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalTypeMASK;
312         return methodDeclaration;
313 }
314 /*
315  * Update the corresponding parse node from parser state which
316  * is about to disappear because of restarting recovery
317  */
318 public void updateFromParserState(){
319
320         if(this.bodyStartsAtHeaderEnd()){
321                 Parser parser = this.parser();
322                 /* might want to recover arguments or thrown exceptions */
323                 if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
324                         /* has consumed the arguments - listed elements must be thrown exceptions */
325                         if (methodDeclaration.sourceEnd == parser.rParenPos) {
326                                 
327                                 // protection for bugs 15142
328                                 int length = parser.astLengthStack[parser.astLengthPtr];
329                                 int astPtr = parser.astPtr - length;
330                                 boolean canConsume = astPtr >= 0;
331                                 if(canConsume) {
332                                         if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
333                                                 canConsume = false;
334                                         }
335                                         for (int i = 1, max = length + 1; i < max; i++) {
336                                                 if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
337                                                         canConsume = false;
338                                                 }
339                                         }
340                                 }
341                                 if (canConsume){
342                                         parser.consumeMethodHeaderThrowsClause(); 
343                                         // will reset typeListLength to zero
344                                         // thus this check will only be performed on first errorCheck after void foo() throws X, Y,
345                                 } else {
346                                         parser.listLength = 0;
347                                 }
348                         } else {
349                                 /* has not consumed arguments yet, listed elements must be arguments */
350                                 if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){
351                                         /* if currentToken is parenthesis this last argument is a method/field signature */
352                                         parser.astLengthStack[parser.astLengthPtr] --; 
353                                         parser.astPtr --; 
354                                         parser.listLength --;
355                                         parser.currentToken = 0;
356                                 }
357                                 int argLength = parser.astLengthStack[parser.astLengthPtr];
358                                 int argStart = parser.astPtr - argLength + 1;
359                                 boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used
360                                 // to compute bodyStart, and thus used to set next checkpoint.
361                                 int count;
362                                 for (count = 0; count < argLength; count++){
363                                         Argument argument = (Argument)parser.astStack[argStart+count];
364                                         /* cannot be an argument if non final */
365                                         char[][] argTypeName = argument.type.getTypeName();
366                                         if ((argument.modifiers & ~AccFinal) != 0
367                                                 || (argTypeName.length == 1
368                                                         && CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){
369                                                 parser.astLengthStack[parser.astLengthPtr] = count; 
370                                                 parser.astPtr = argStart+count-1; 
371                                                 parser.listLength = count;
372                                                 parser.currentToken = 0;
373                                                 break;
374                                         }
375                                         if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
376                                 }
377                                 if (parser.listLength > 0 && parser.astLengthPtr > 0){
378                                         
379                                         // protection for bugs 15142
380                                         int length = parser.astLengthStack[parser.astLengthPtr];
381                                         int astPtr = parser.astPtr - length;
382                                         boolean canConsume = astPtr >= 0;
383                                         if(canConsume) {
384                                                 if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
385                                                         canConsume = false;
386                                                 }
387                                                 for (int i = 1, max = length + 1; i < max; i++) {
388                                                         if(!(parser.astStack[astPtr + i ] instanceof Argument)) {
389                                                                 canConsume = false;
390                                                         }
391                                                 }
392                                         }
393                                         if(canConsume) {
394                                                 parser.consumeMethodHeaderParameters();
395                                                 /* fix-up positions, given they were updated against rParenPos, which did not get set */
396                                                 if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */
397                                                         methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd;
398                                                         methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1;
399                                                         parser.lastCheckPoint = methodDeclaration.bodyStart;
400                                                 }
401                                         }
402                                 }
403                         }
404                 }
405         }
406 }
407 /*
408  * An opening brace got consumed, might be the expected opening one of the current element,
409  * in which case the bodyStart is updated.
410  */
411 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
412
413         /* in case the opening brace is close enough to the signature */
414         if (bracketBalance == 0){
415                 /*
416                         if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd) 
417                                 != parser.scanner.searchLineNumber(braceEnd)){
418                  */
419                 switch(parser().lastIgnoredToken){
420                         case -1 :
421                         case TokenNamethrows :
422                                 break;
423                         default:
424                                 this.foundOpeningBrace = true;                          
425                                 bracketBalance = 1; // pretend the brace was already there
426                 }
427         }       
428         return super.updateOnOpeningBrace(braceStart, braceEnd);
429 }
430 public void updateParseTree(){
431         this.updatedMethodDeclaration();
432 }
433 /*
434  * Update the declarationSourceEnd of the corresponding parse node
435  */
436 public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
437         if (this.methodDeclaration.declarationSourceEnd == 0) {
438                 if(parser().rBraceSuccessorStart >= braceEnd) {
439                         this.methodDeclaration.declarationSourceEnd = parser().rBraceEnd;
440                         this.methodDeclaration.bodyEnd = parser().rBraceStart;
441                 } else {
442                         this.methodDeclaration.declarationSourceEnd = braceEnd;
443                         this.methodDeclaration.bodyEnd  = braceStart - 1;
444                 }
445         }
446 }
447 }