removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / parser / RecoveredMethod.java
diff --git a/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java
new file mode 100644 (file)
index 0000000..b76bf04
--- /dev/null
@@ -0,0 +1,447 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.parser;
+
+import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.SuperReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.lookup.BaseTypes;
+import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
+
+/**
+ * Internal method structure for parsing recovery 
+ */
+
+public class RecoveredMethod extends RecoveredElement implements CompilerModifiers, TerminalTokens, BaseTypes {
+
+       public AbstractMethodDeclaration methodDeclaration;
+
+       public RecoveredType[] localTypes;
+       public int localTypeCount;
+
+       public RecoveredBlock methodBody;
+       public boolean discardBody = true;
+
+public RecoveredMethod(AbstractMethodDeclaration methodDeclaration, RecoveredElement parent, int bracketBalance, Parser parser){
+       super(parent, bracketBalance, parser);
+       this.methodDeclaration = methodDeclaration;
+       this.foundOpeningBrace = !bodyStartsAtHeaderEnd();
+       if(this.foundOpeningBrace) {
+               this.bracketBalance++;
+       }
+}
+/*
+ * Record a nested block declaration
+ */
+public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
+
+       /* default behavior is to delegate recording to parent if any,
+       do not consider elements passed the known end (if set)
+       it must be belonging to an enclosing element 
+       */
+       if (methodDeclaration.declarationSourceEnd > 0
+               && nestedBlockDeclaration.sourceStart
+                       > methodDeclaration.declarationSourceEnd){
+                               if (this.parent == null){
+                                       return this; // ignore
+                               } else {
+                                       return this.parent.add(nestedBlockDeclaration, bracketBalanceValue);
+                               }
+       }
+       /* consider that if the opening brace was not found, it is there */
+       if (!foundOpeningBrace){
+               foundOpeningBrace = true;
+               this.bracketBalance++;
+       }
+
+       methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
+       if (nestedBlockDeclaration.sourceEnd == 0) return methodBody;
+       return this;
+}
+/*
+ * Record a field declaration
+ */
+public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) {
+
+       /* local variables inside method can only be final and non void */
+       char[][] fieldTypeName; 
+       if ((fieldDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
+               || (fieldDeclaration.type == null) // initializer
+               || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void
+                       && CharOperation.equals(fieldTypeName[0], VoidBinding.sourceName()))){ 
+
+               if (this.parent == null){
+                       return this; // ignore
+               } else {
+                       this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(fieldDeclaration.declarationSourceStart - 1));
+                       return this.parent.add(fieldDeclaration, bracketBalanceValue);
+               }
+       }
+       /* default behavior is to delegate recording to parent if any,
+       do not consider elements passed the known end (if set)
+       it must be belonging to an enclosing element 
+       */
+       if (methodDeclaration.declarationSourceEnd > 0
+               && fieldDeclaration.declarationSourceStart
+                       > methodDeclaration.declarationSourceEnd){
+               if (this.parent == null){
+                       return this; // ignore
+               } else {
+                       return this.parent.add(fieldDeclaration, bracketBalanceValue);
+               }
+       }
+       /* consider that if the opening brace was not found, it is there */
+       if (!foundOpeningBrace){
+               foundOpeningBrace = true;
+               this.bracketBalance++;
+       }
+       // still inside method, treat as local variable
+       return this; // ignore
+}
+/*
+ * Record a local declaration - regular method should have been created a block body
+ */
+public RecoveredElement add(LocalDeclaration localDeclaration, int bracketBalanceValue) {
+
+       /* local variables inside method can only be final and non void */
+/*     
+       char[][] localTypeName; 
+       if ((localDeclaration.modifiers & ~AccFinal) != 0 // local var can only be final 
+               || (localDeclaration.type == null) // initializer
+               || ((localTypeName = localDeclaration.type.getTypeName()).length == 1 // non void
+                       && CharOperation.equals(localTypeName[0], VoidBinding.sourceName()))){ 
+
+               if (this.parent == null){
+                       return this; // ignore
+               } else {
+                       this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
+                       return this.parent.add(localDeclaration, bracketBalance);
+               }
+       }
+*/
+       /* do not consider a type starting passed the type end (if set)
+               it must be belonging to an enclosing type */
+       if (methodDeclaration.declarationSourceEnd != 0 
+               && localDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
+                       
+               if (this.parent == null) {
+                       return this; // ignore
+               } else {
+                       return this.parent.add(localDeclaration, bracketBalanceValue);
+               }
+       }
+       if (methodBody == null){
+               Block block = new Block(0);
+               block.sourceStart = methodDeclaration.bodyStart;
+               RecoveredElement currentBlock = this.add(block, 1);
+               if (this.bracketBalance > 0){
+                       for (int i = 0; i < this.bracketBalance - 1; i++){
+                               currentBlock = currentBlock.add(new Block(0), 1);
+                       }
+                       this.bracketBalance = 1;
+               }
+               return currentBlock.add(localDeclaration, bracketBalanceValue);
+       }
+       return methodBody.add(localDeclaration, bracketBalanceValue, true);
+}
+/*
+ * Record a statement - regular method should have been created a block body
+ */
+public RecoveredElement add(Statement statement, int bracketBalanceValue) {
+
+       /* do not consider a type starting passed the type end (if set)
+               it must be belonging to an enclosing type */
+       if (methodDeclaration.declarationSourceEnd != 0 
+               && statement.sourceStart > methodDeclaration.declarationSourceEnd){
+
+               if (this.parent == null) {
+                       return this; // ignore
+               } else {
+                       return this.parent.add(statement, bracketBalanceValue);
+               }
+       }
+       if (methodBody == null){
+               Block block = new Block(0);
+               block.sourceStart = methodDeclaration.bodyStart;
+               RecoveredElement currentBlock = this.add(block, 1);
+               if (this.bracketBalance > 0){
+                       for (int i = 0; i < this.bracketBalance - 1; i++){
+                               currentBlock = currentBlock.add(new Block(0), 1);
+                       }
+                       this.bracketBalance = 1;
+               }
+               return currentBlock.add(statement, bracketBalanceValue);
+       }
+       return methodBody.add(statement, bracketBalanceValue, true);    
+}
+public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
+
+       /* do not consider a type starting passed the type end (if set)
+               it must be belonging to an enclosing type */
+       if (methodDeclaration.declarationSourceEnd != 0 
+               && typeDeclaration.declarationSourceStart > methodDeclaration.declarationSourceEnd){
+                       
+               if (this.parent == null) {
+                       return this; // ignore
+               }
+               return this.parent.add(typeDeclaration, bracketBalanceValue);
+       }
+       if ((typeDeclaration.bits & ASTNode.IsLocalTypeMASK) != 0){
+               if (methodBody == null){
+                       Block block = new Block(0);
+                       block.sourceStart = methodDeclaration.bodyStart;
+                       this.add(block, 1);
+               }
+               return methodBody.add(typeDeclaration, bracketBalanceValue, true);      
+       }
+       if (typeDeclaration.isInterface()) {
+               this.updateSourceEndIfNecessary(this.previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1));
+               if (this.parent == null) {
+                       return this; // ignore
+               }
+               // close the constructor
+               return this.parent.add(typeDeclaration, bracketBalanceValue);
+       }
+       if (localTypes == null) {
+               localTypes = new RecoveredType[5];
+               localTypeCount = 0;
+       } else {
+               if (localTypeCount == localTypes.length) {
+                       System.arraycopy(
+                               localTypes, 
+                               0, 
+                               (localTypes = new RecoveredType[2 * localTypeCount]), 
+                               0, 
+                               localTypeCount); 
+               }
+       }
+       RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue);
+       localTypes[localTypeCount++] = element;
+
+       /* consider that if the opening brace was not found, it is there */
+       if (!foundOpeningBrace){
+               foundOpeningBrace = true;
+               this.bracketBalance++;
+       }
+       return element;
+}
+public boolean bodyStartsAtHeaderEnd(){
+       return methodDeclaration.bodyStart == methodDeclaration.sourceEnd+1;
+}
+/* 
+ * Answer the associated parsed structure
+ */
+public ASTNode parseTree(){
+       return methodDeclaration;
+}
+/*
+ * Answer the very source end of the corresponding parse node
+ */
+public int sourceEnd(){
+       return this.methodDeclaration.declarationSourceEnd;
+}
+public String toString(int tab) {
+       StringBuffer result = new StringBuffer(tabString(tab));
+       result.append("Recovered method:\n"); //$NON-NLS-1$
+       this.methodDeclaration.print(tab + 1, result);
+       if (this.localTypes != null) {
+               for (int i = 0; i < this.localTypeCount; i++) {
+                       result.append("\n"); //$NON-NLS-1$
+                       result.append(this.localTypes[i].toString(tab + 1));
+               }
+       }
+       if (this.methodBody != null) {
+               result.append("\n"); //$NON-NLS-1$
+               result.append(this.methodBody.toString(tab + 1));
+       }
+       return result.toString();
+}
+/*
+ * Update the bodyStart of the corresponding parse node
+ */
+public void updateBodyStart(int bodyStart){
+       this.foundOpeningBrace = true;          
+       this.methodDeclaration.bodyStart = bodyStart;
+}
+public AbstractMethodDeclaration updatedMethodDeclaration(){
+
+       if (methodBody != null){
+               Block block = methodBody.updatedBlock();
+               if (block != null){
+                       methodDeclaration.statements = block.statements;
+
+                       /* first statement might be an explict constructor call destinated to a special slot */
+                       if (methodDeclaration.isConstructor()) {
+                               ConstructorDeclaration constructor = (ConstructorDeclaration)methodDeclaration;
+                               if (methodDeclaration.statements != null
+                                       && methodDeclaration.statements[0] instanceof ExplicitConstructorCall){
+                                       constructor.constructorCall = (ExplicitConstructorCall)methodDeclaration.statements[0];
+                                       int length = methodDeclaration.statements.length;
+                                       System.arraycopy(
+                                               methodDeclaration.statements, 
+                                               1, 
+                                               (methodDeclaration.statements = new Statement[length-1]),
+                                               0,
+                                               length-1);
+                                       }
+                                       if (constructor.constructorCall == null){ // add implicit constructor call
+                                               constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
+                                       }
+                       }
+               }
+       }
+       if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalTypeMASK;
+       return methodDeclaration;
+}
+/*
+ * Update the corresponding parse node from parser state which
+ * is about to disappear because of restarting recovery
+ */
+public void updateFromParserState(){
+
+       if(this.bodyStartsAtHeaderEnd()){
+               Parser parser = this.parser();
+               /* might want to recover arguments or thrown exceptions */
+               if (parser.listLength > 0 && parser.astLengthPtr > 0){ // awaiting interface type references
+                       /* has consumed the arguments - listed elements must be thrown exceptions */
+                       if (methodDeclaration.sourceEnd == parser.rParenPos) {
+                               
+                               // protection for bugs 15142
+                               int length = parser.astLengthStack[parser.astLengthPtr];
+                               int astPtr = parser.astPtr - length;
+                               boolean canConsume = astPtr >= 0;
+                               if(canConsume) {
+                                       if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
+                                               canConsume = false;
+                                       }
+                                       for (int i = 1, max = length + 1; i < max; i++) {
+                                               if(!(parser.astStack[astPtr + i ] instanceof TypeReference)) {
+                                                       canConsume = false;
+                                               }
+                                       }
+                               }
+                               if (canConsume){
+                                       parser.consumeMethodHeaderThrowsClause(); 
+                                       // will reset typeListLength to zero
+                                       // thus this check will only be performed on first errorCheck after void foo() throws X, Y,
+                               } else {
+                                       parser.listLength = 0;
+                               }
+                       } else {
+                               /* has not consumed arguments yet, listed elements must be arguments */
+                               if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON){
+                                       /* if currentToken is parenthesis this last argument is a method/field signature */
+                                       parser.astLengthStack[parser.astLengthPtr] --; 
+                                       parser.astPtr --; 
+                                       parser.listLength --;
+                                       parser.currentToken = 0;
+                               }
+                               int argLength = parser.astLengthStack[parser.astLengthPtr];
+                               int argStart = parser.astPtr - argLength + 1;
+                               boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used
+                               // to compute bodyStart, and thus used to set next checkpoint.
+                               int count;
+                               for (count = 0; count < argLength; count++){
+                                       Argument argument = (Argument)parser.astStack[argStart+count];
+                                       /* cannot be an argument if non final */
+                                       char[][] argTypeName = argument.type.getTypeName();
+                                       if ((argument.modifiers & ~AccFinal) != 0
+                                               || (argTypeName.length == 1
+                                                       && CharOperation.equals(argTypeName[0], VoidBinding.sourceName()))){
+                                               parser.astLengthStack[parser.astLengthPtr] = count; 
+                                               parser.astPtr = argStart+count-1; 
+                                               parser.listLength = count;
+                                               parser.currentToken = 0;
+                                               break;
+                                       }
+                                       if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1;
+                               }
+                               if (parser.listLength > 0 && parser.astLengthPtr > 0){
+                                       
+                                       // protection for bugs 15142
+                                       int length = parser.astLengthStack[parser.astLengthPtr];
+                                       int astPtr = parser.astPtr - length;
+                                       boolean canConsume = astPtr >= 0;
+                                       if(canConsume) {
+                                               if((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) {
+                                                       canConsume = false;
+                                               }
+                                               for (int i = 1, max = length + 1; i < max; i++) {
+                                                       if(!(parser.astStack[astPtr + i ] instanceof Argument)) {
+                                                               canConsume = false;
+                                                       }
+                                               }
+                                       }
+                                       if(canConsume) {
+                                               parser.consumeMethodHeaderParameters();
+                                               /* fix-up positions, given they were updated against rParenPos, which did not get set */
+                                               if (parser.currentElement == this){ // parameter addition might have added an awaiting (no return type) method - see 1FVXQZ4 */
+                                                       methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length-1].sourceEnd;
+                                                       methodDeclaration.bodyStart = methodDeclaration.sourceEnd+1;
+                                                       parser.lastCheckPoint = methodDeclaration.bodyStart;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+/*
+ * An opening brace got consumed, might be the expected opening one of the current element,
+ * in which case the bodyStart is updated.
+ */
+public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
+
+       /* in case the opening brace is close enough to the signature */
+       if (bracketBalance == 0){
+               /*
+                       if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd) 
+                               != parser.scanner.searchLineNumber(braceEnd)){
+                */
+               switch(parser().lastIgnoredToken){
+                       case -1 :
+                       case TokenNamethrows :
+                               break;
+                       default:
+                               this.foundOpeningBrace = true;                          
+                               bracketBalance = 1; // pretend the brace was already there
+               }
+       }       
+       return super.updateOnOpeningBrace(braceStart, braceEnd);
+}
+public void updateParseTree(){
+       this.updatedMethodDeclaration();
+}
+/*
+ * Update the declarationSourceEnd of the corresponding parse node
+ */
+public void updateSourceEndIfNecessary(int braceStart, int braceEnd){
+       if (this.methodDeclaration.declarationSourceEnd == 0) {
+               if(parser().rBraceSuccessorStart >= braceEnd) {
+                       this.methodDeclaration.declarationSourceEnd = parser().rBraceEnd;
+                       this.methodDeclaration.bodyEnd = parser().rBraceStart;
+               } else {
+                       this.methodDeclaration.declarationSourceEnd = braceEnd;
+                       this.methodDeclaration.bodyEnd  = braceStart - 1;
+               }
+       }
+}
+}