KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > parser > RecoveredMethod


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.MemberValuePair;
23 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
24 import org.eclipse.jdt.internal.compiler.ast.Statement;
25 import org.eclipse.jdt.internal.compiler.ast.SuperReference;
26 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
27 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
28 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
29 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
30 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
31 import org.eclipse.jdt.internal.compiler.util.Util;
32
33 /**
34  * Internal method structure for parsing recovery
35  */

36
37 public class RecoveredMethod extends RecoveredElement implements TerminalTokens {
38
39     public AbstractMethodDeclaration methodDeclaration;
40
41     public RecoveredType[] localTypes;
42     public int localTypeCount;
43
44     public RecoveredBlock methodBody;
45     public boolean discardBody = true;
46
47 public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
48     super(parent, bracketBalance, parser);
49     this.methodDeclaration = methodDeclaration;
50     this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
51     if(this.foundOpeningBrace) {
52         this.bracketBalance++;
53     }
54 }
55 /*
56  * Record a nested block declaration
57  */

58 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
59
60     /* default behavior is to delegate recording to parent if any,
61     do not consider elements passed the known end (if set)
62     it must be belonging to an enclosing element
63     */

64     if (methodDeclaration.declarationSourceEnd > 0
65         && nestedBlockDeclaration.sourceStart
66             > methodDeclaration.declarationSourceEnd){
67                 if (this.parent == null){
68                     return this; // ignore
69
} else {
70                     return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
71                 }
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
79     methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
80     if (nestedBlockDeclaration.sourceEnd == 0) return methodBody;
81     return this;
82 }
83 /*
84  * Record a field declaration
85  */

86 public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
87
88     /* local variables inside method can only be final and non void */
89     char[][] fieldTypeName;
90     if ((fieldDeclaration.modifiers & ~ClassFileConstants.AccFinal) != 0 // local var can only be final
91
|| (fieldDeclaration.type == null) // initializer
92
|| ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void
93
&& CharOperation.equals(fieldTypeName[0], TypeBinding.VOID.sourceName()))){
94
95         if (this.parent == null){
96             return this; // ignore
97
} else {
98             this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
99             return this.parent.add(fieldDeclaration, bracketBalanceValue);
100         }
101     }
102     /* default behavior is to delegate recording to parent if any,
103     do not consider elements passed the known end (if set)
104     it must be belonging to an enclosing element
105     */

106     if (methodDeclaration.declarationSourceEnd > 0
107         && fieldDeclaration.declarationSourceStart
108             > methodDeclaration.declarationSourceEnd){
109         if (this.parent == null){
110             return this; // ignore
111
} else {
112             return this.parent.add(fieldDeclaration, bracketBalanceValue);
113         }
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     // still inside method, treat as local variable
121
return this; // ignore
122
}
123 /*
124  * Record a local declaration - regular method should have been created a block body
125  */

126 public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
127
128     /* local variables inside method can only be final and non void */
129 /*
130     char[][] localTypeName;
131     if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final
132         || (localDeclaration.type == null) // initializer
133         || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void
134             && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){
135
136         if (this.parent == null){
137             return this; // ignore
138         } else {
139             this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
140             return this.parent.add(localDeclaration, bracketBalance);
141         }
142     }
143 */

144     /* do not consider a type starting passed the type end (if set)
145         it must be belonging to an enclosing type */

146     if (methodDeclaration.declarationSourceEnd != 0
147         && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
148             
149         if (this.parent == null) {
150             return this; // ignore
151
} else {
152             return this.parent.add(localDeclaration, bracketBalanceValue);
153         }
154     }
155     if (methodBody == null){
156         Block block = new Block(0);
157         block.sourceStart = methodDeclaration.bodyStart;
158         RecoveredElement currentBlock = this.add(block, 1);
159         if (this.bracketBalance > 0){
160             for (int i = 0; i < this.bracketBalance - 1; i++){
161                 currentBlock = currentBlock.add(new Block(0), 1);
162             }
163             this.bracketBalance = 1;
164         }
165         return currentBlock.add(localDeclaration, bracketBalanceValue);
166     }
167     return methodBody.add(localDeclaration, bracketBalanceValue, true);
168 }
169 /*
170  * Record a statement - regular method should have been created a block body
171  */

172 public RecoveredElement add(Statement statement, int bracketBalanceValue) {
173
174     /* do not consider a type starting passed the type end (if set)
175         it must be belonging to an enclosing type */

176     if (methodDeclaration.declarationSourceEnd != 0
177         && statement.sourceStart > methodDeclaration.declarationSourceEnd){
178
179         if (this.parent == null) {
180             return this; // ignore
181
} else {
182             return this.parent.add(statement, bracketBalanceValue);
183         }
184     }
185     if (methodBody == null){
186         Block block = new Block(0);
187         block.sourceStart = methodDeclaration.bodyStart;
188         RecoveredElement currentBlock = this.add(block, 1);
189         if (this.bracketBalance > 0){
190             for (int i = 0; i < this.bracketBalance - 1; i++){
191                 currentBlock = currentBlock.add(new Block(0), 1);
192             }
193             this.bracketBalance = 1;
194         }
195         return currentBlock.add(statement, bracketBalanceValue);
196     }
197     return methodBody.add(statement, bracketBalanceValue, true);
198 }
199 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
200
201     /* do not consider a type starting passed the type end (if set)
202         it must be belonging to an enclosing type */

203     if (methodDeclaration.declarationSourceEnd != 0
204         && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
205             
206         if (this.parent == null) {
207             return this; // ignore
208
}
209         return this.parent.add(typeDeclaration, bracketBalanceValue);
210     }
211     if ((typeDeclaration.bits & ASTNode.IsLocalType) != 0 || this.parser().methodRecoveryActivated || this.parser().statementRecoveryActivated){
212         if (methodBody == null){
213             Block block = new Block(0);
214             block.sourceStart = methodDeclaration.bodyStart;
215             this.add(block, 1);
216         }
217         return methodBody.add(typeDeclaration, bracketBalanceValue, true);
218     }
219     switch (TypeDeclaration.kind(typeDeclaration.modifiers)) {
220         case TypeDeclaration.INTERFACE_DECL :
221         case TypeDeclaration.ANNOTATION_TYPE_DECL :
222             this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
223             if (this.parent == null) {
224                 return this; // ignore
225
}
226             // close the constructor
227
return this.parent.add(typeDeclaration, bracketBalanceValue);
228     }
229     if (localTypes == null) {
230         localTypes = new RecoveredType[5];
231         localTypeCount = 0;
232     } else {
233         if (localTypeCount == localTypes.length) {
234             System.arraycopy(
235                 localTypes,
236                 0,
237                 (localTypes = new RecoveredType[2 * localTypeCount]),
238                 0,
239                 localTypeCount);
240         }
241     }
242     RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
243     localTypes[localTypeCount++] = element;
244
245     /* consider that if the opening brace was not found, it is there */
246     if (!foundOpeningBrace){
247         foundOpeningBrace = true;
248         this.bracketBalance++;
249     }
250     return element;
251 }
252 public boolean bodyStartsAtHeaderEnd(){
253     return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1;
254 }
255 /*
256  * Answer the associated parsed structure
257  */

258 public ASTNode parseTree(){
259     return methodDeclaration;
260 }
261 /*
262  * Answer the very source end of the corresponding parse node
263  */

264 public int sourceEnd(){
265     return this.methodDeclaration.declarationSourceEnd;
266 }
267 public String JavaDoc toString(int tab) {
268     StringBuffer JavaDoc result = new StringBuffer JavaDoc(tabString(tab));
269     result.append("Recovered method:\n"); //$NON-NLS-1$
270
this.methodDeclaration.print(tab + 1, result);
271     if (this.localTypes != null) {
272         for (int i = 0; i < this.localTypeCount; i++) {
273             result.append("\n"); //$NON-NLS-1$
274
result.append(this.localTypes[i].toString(tab + 1));
275         }
276     }
277     if (this.methodBody != null) {
278         result.append("\n"); //$NON-NLS-1$
279
result.append(this.methodBody.toString(tab + 1));
280     }
281     return result.toString();
282 }
283 /*
284  * Update the bodyStart of the corresponding parse node
285  */

286 public void updateBodyStart(int bodyStart){
287     this.foundOpeningBrace = true;
288     this.methodDeclaration.bodyStart = bodyStart;
289 }
290 public AbstractMethodDeclaration updatedMethodDeclaration(){
291
292     if (methodBody != null){
293         Block block = methodBody.updatedBlock();
294         if (block != null){
295             methodDeclaration.statements = block.statements;
296
297             /* first statement might be an explict constructor call destinated to a special slot */
298             if (methodDeclaration.isConstructor()) {
299                 ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration;
300                 if (methodDeclaration.statements != null
301                     && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){
302                     constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0];
303                     int length = methodDeclaration.statements.length;
304                     System.arraycopy(
305                         methodDeclaration.statements,
306                         1,
307                         (methodDeclaration.statements = new Statement[length-1]),
308                         0,
309                         length-1);
310                     }
311                     if (constructor.constructorCall == null){ // add implicit constructor call
312
constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
313                     }
314             }
315         }
316     }
317     if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalType;
318     return methodDeclaration;
319 }
320 /*
321  * Update the corresponding parse node from parser state which
322  * is about to disappear because of restarting recovery
323  */

324 public void updateFromParserState(){
325     // if parent is null then recovery already occured in diet parser.
326
if(this.bodyStartsAtHeaderEnd() && this.parent != null){
327         Parser parser = this.parser();
328         /* might want to recover arguments or thrown exceptions */
329         if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
330
/* has consumed the arguments - listed elements must be thrown exceptions */
331             if (methodDeclaration.sourceEnd == parser.rParenPos) {
332                 
333                 // protection for bugs 15142
334
int length = parser.astLengthStack[parser.astLengthPtr];
335                 int astPtr = parser.astPtr - length;
336                 boolean canConsume = astPtr >= 0;
337                 if(canConsume) {
338                     if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
339                         canConsume = false;
340                     }
341                     for (int i = 1, max = length + 1; i < max; i++) {
342                         if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
343                             canConsume = false;
344                         }
345                     }
346                 }
347                 if (canConsume){
348                     parser.consumeMethodHeaderThrowsClause();
349                     // will reset typeListLength to zero
350
// thus this check will only be performed on first errorCheck after void foo() throws X, Y,
351
} else {
352                     parser.listLength = 0;
353                 }
354             } else {
355                 /* has not consumed arguments yet, listed elements must be arguments */
356                 if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){
357                     /* if currentToken is parenthesis this last argument is a method/field signature */
358                     parser.astLengthStack[parser.astLengthPtr] --;
359                     parser.astPtr --;
360                     parser.listLength --;
361                     parser.currentToken = 0;
362                 }
363                 int argLength = parser.astLengthStack[parser.astLengthPtr];
364                 int argStart = parser.astPtr - argLength + 1;
365                 boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used
366

367                 // remove unfinished annotation nodes
368
MemberValuePair[] memberValuePairs = null;
369                 if (argLength > 0 && parser.astStack[parser.astPtr] instanceof MemberValuePair) {
370                     System.arraycopy(parser.astStack, argStart, memberValuePairs = new MemberValuePair[argLength], 0, argLength);
371                     parser.astLengthPtr--;
372                     parser.astPtr -= argLength;
373                     
374                     argLength = parser.astLengthStack[parser.astLengthPtr];
375                     argStart = parser.astPtr - argLength + 1;
376                     needUpdateRParenPos = true;
377                 }
378                 
379                 // to compute bodyStart, and thus used to set next checkpoint.
380
int count;
381                 for (count = 0; count < argLength; count++){
382                     ASTNode aNode = parser.astStack[argStart+count];
383                     if(aNode instanceof Argument) {
384                         Argument argument = (Argument)aNode;
385                         /* cannot be an argument if non final */
386                         char[][] argTypeName = argument.type.getTypeName();
387                         if ((argument.modifiers & ~ClassFileConstants.AccFinal) != 0
388                             || (argTypeName.length == 1
389                                 && CharOperation.equals(argTypeName[0], TypeBinding.VOID.sourceName()))){
390                             parser.astLengthStack[parser.astLengthPtr] = count;
391                             parser.astPtr = argStart+count-1;
392                             parser.listLength = count;
393                             parser.currentToken = 0;
394                             break;
395                         }
396                         if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
397                     } else {
398                         parser.astLengthStack[parser.astLengthPtr] = count;
399                         parser.astPtr = argStart+count-1;
400                         parser.listLength = count;
401                         parser.currentToken = 0;
402                         break;
403                     }
404                 }
405                 if (parser.listLength > 0 && parser.astLengthPtr > 0){
406                     
407                     // protection for bugs 15142
408
int length = parser.astLengthStack[parser.astLengthPtr];
409                     int astPtr = parser.astPtr - length;
410                     boolean canConsume = astPtr >= 0;
411                     if(canConsume) {
412                         if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
413                             canConsume = false;
414                         }
415                         for (int i = 1, max = length + 1; i < max; i++) {
416                             if(!(parser.astStack[astPtr + i ] instanceof Argument)) {
417                                 canConsume = false;
418                             }
419                         }
420                     }
421                     if(canConsume) {
422                         parser.consumeMethodHeaderRightParen();
423                         /* fix-up positions, given they were updated against rParenPos, which did not get set */
424                         if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */
425
methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd;
426                             methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1;
427                             parser.lastCheckPoint = methodDeclaration.bodyStart;
428                         }
429                     }
430                 }
431                 
432                 if(memberValuePairs != null) {
433                     System.arraycopy(memberValuePairs, 0, parser.astStack, parser.astPtr + 1, memberValuePairs.length);
434                     parser.astPtr += memberValuePairs.length;
435                     parser.astLengthStack[++parser.astLengthPtr] = memberValuePairs.length;
436                 }
437             }
438         }
439     }
440 }
441 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
442     if(this.methodDeclaration.isAnnotationMethod()) {
443         this.updateSourceEndIfNecessary(braceStart, braceEnd);
444         if(!this.foundOpeningBrace && this.parent != null) {
445             return this.parent.updateOnClosingBrace(braceStart, braceEnd);
446         }
447         return this;
448     }
449     if(this.parent != null && this.parent instanceof RecoveredType) {
450         int modifiers = ((RecoveredType)this.parent).typeDeclaration.modifiers;
451         if (TypeDeclaration.kind(modifiers) == TypeDeclaration.INTERFACE_DECL) {
452             if (!this.foundOpeningBrace) {
453                 this.updateSourceEndIfNecessary(braceStart - 1, braceStart - 1);
454                 return this.parent.updateOnClosingBrace(braceStart, braceEnd);
455             }
456         }
457     }
458     return super.updateOnClosingBrace(braceStart, braceEnd);
459 }
460 /*
461  * An opening brace got consumed, might be the expected opening one of the current element,
462  * in which case the bodyStart is updated.
463  */

464 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
465
466     /* in case the opening brace is close enough to the signature */
467     if (bracketBalance == 0){
468         /*
469             if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd)
470                 != parser.scanner.searchLineNumber(braceEnd)){
471          */

472         switch(parser().lastIgnoredToken){
473             case -1 :
474             case TokenNamethrows :
475                 break;
476             default:
477                 this.foundOpeningBrace = true;
478                 bracketBalance = 1; // pretend the brace was already there
479
}
480     }
481     return super.updateOnOpeningBrace(braceStart, braceEnd);
482 }
483 public void updateParseTree(){
484     this.updatedMethodDeclaration();
485 }
486 /*
487  * Update the declarationSourceEnd of the corresponding parse node
488  */

489 public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
490     if (this.methodDeclaration.declarationSourceEnd == 0) {
491         if(parser().rBraceSuccessorStart >= braceEnd) {
492             this.methodDeclaration.declarationSourceEnd = parser().rBraceEnd;
493             this.methodDeclaration.bodyEnd = parser().rBraceStart;
494         } else {
495             this.methodDeclaration.declarationSourceEnd = braceEnd;
496             this.methodDeclaration.bodyEnd = braceStart - 1;
497         }
498     }
499 }
500 void attach(TypeParameter[] parameters, int startPos) {
501     if(methodDeclaration.modifiers != ClassFileConstants.AccDefault) return;
502     
503     int lastParameterEnd = parameters[parameters.length - 1].sourceEnd;
504     
505     Parser parser = this.parser();
506     Scanner scanner = parser.scanner;
507     if(Util.getLineNumber(methodDeclaration.declarationSourceStart, scanner.lineEnds, 0, scanner.linePtr)
508             != Util.getLineNumber(lastParameterEnd, scanner.lineEnds, 0, scanner.linePtr)) return;
509     
510     if(parser.modifiersSourceStart > lastParameterEnd
511             && parser.modifiersSourceStart < methodDeclaration.declarationSourceStart) return;
512     
513     if (this.methodDeclaration instanceof MethodDeclaration) {
514         ((MethodDeclaration)this.methodDeclaration).typeParameters = parameters;
515         this.methodDeclaration.declarationSourceStart = startPos;
516     } else if (this.methodDeclaration instanceof ConstructorDeclaration){
517         ((ConstructorDeclaration)this.methodDeclaration).typeParameters = parameters;
518         this.methodDeclaration.declarationSourceStart = startPos;
519     }
520 }
521 }
522
Popular Tags