| /******************************************************************************* |
| * Copyright (c) 2000, 2013 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * $Id: RecoveredMethod.java 23404 2010-02-03 14:10:22Z stephan $ |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Fraunhofer FIRST - extended API and implementation |
| * Technical University Berlin - extended API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.parser; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.eclipse.jdt.core.compiler.*; |
| import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.Annotation; |
| 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.MemberValuePair; |
| import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| 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.TypeParameter; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| import org.eclipse.jdt.internal.compiler.util.Util; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator; |
| |
| /** |
| * Internal method structure for parsing recovery |
| */ |
| |
| @SuppressWarnings("rawtypes") |
| public class RecoveredMethod extends RecoveredElement implements TerminalTokens { |
| |
| public AbstractMethodDeclaration methodDeclaration; |
| |
| public RecoveredAnnotation[] annotations; |
| public int annotationCount; |
| |
| public int modifiers; |
| public int modifiersStart; |
| |
| public RecoveredType[] localTypes; |
| public int localTypeCount; |
| |
| public RecoveredBlock methodBody; |
| public boolean discardBody = true; |
| |
| int pendingModifiers; |
| int pendingModifersSourceStart = -1; |
| RecoveredAnnotation[] pendingAnnotations; |
| int pendingAnnotationCount; |
| |
| 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 (this.methodDeclaration.declarationSourceEnd > 0 |
| && nestedBlockDeclaration.sourceStart |
| > this.methodDeclaration.declarationSourceEnd){ |
| resetPendingModifiers(); |
| 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 (!this.foundOpeningBrace){ |
| this.foundOpeningBrace = true; |
| this.bracketBalance++; |
| } |
| |
| this.methodBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue); |
| if (nestedBlockDeclaration.sourceEnd == 0) return this.methodBody; |
| return this; |
| } |
| /* |
| * Record a field declaration |
| */ |
| public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { |
| resetPendingModifiers(); |
| |
| /* local variables inside method can only be final and non void */ |
| char[][] fieldTypeName; |
| if ((fieldDeclaration.modifiers & ~ClassFileConstants.AccFinal) != 0 // local var can only be final |
| || (fieldDeclaration.type == null) // initializer |
| || ((fieldTypeName = fieldDeclaration.type.getTypeName()).length == 1 // non void |
| && CharOperation.equals(fieldTypeName[0], TypeBinding.VOID.sourceName()))){ |
| if (this.parent == null){ |
| return this; // ignore |
| } else { |
| this.updateSourceEndIfNecessary(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 (this.methodDeclaration.declarationSourceEnd > 0 |
| && fieldDeclaration.declarationSourceStart |
| > this.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 (!this.foundOpeningBrace){ |
| this.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) { |
| resetPendingModifiers(); |
| |
| /* 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 (this.methodDeclaration.declarationSourceEnd != 0 |
| && localDeclaration.declarationSourceStart > this.methodDeclaration.declarationSourceEnd){ |
| |
| if (this.parent == null) { |
| return this; // ignore |
| } else { |
| return this.parent.add(localDeclaration, bracketBalanceValue); |
| } |
| } |
| if (this.methodBody == null){ |
| Block block = new Block(0); |
| block.sourceStart = this.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 this.methodBody.add(localDeclaration, bracketBalanceValue, true); |
| } |
| /* |
| * Record a statement - regular method should have been created a block body |
| */ |
| public RecoveredElement add(Statement statement, int bracketBalanceValue) { |
| resetPendingModifiers(); |
| |
| /* do not consider a type starting passed the type end (if set) |
| it must be belonging to an enclosing type */ |
| if (this.methodDeclaration.declarationSourceEnd != 0 |
| && statement.sourceStart > this.methodDeclaration.declarationSourceEnd){ |
| |
| if (this.parent == null) { |
| return this; // ignore |
| } else { |
| return this.parent.add(statement, bracketBalanceValue); |
| } |
| } |
| if (this.methodBody == null){ |
| Block block = new Block(0); |
| block.sourceStart = this.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 this.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 (this.methodDeclaration.declarationSourceEnd != 0 |
| && typeDeclaration.declarationSourceStart > this.methodDeclaration.declarationSourceEnd){ |
| |
| if (this.parent == null) { |
| return this; // ignore |
| } |
| return this.parent.add(typeDeclaration, bracketBalanceValue); |
| } |
| if ((typeDeclaration.bits & ASTNode.IsLocalType) != 0 || parser().methodRecoveryActivated || parser().statementRecoveryActivated){ |
| if (this.methodBody == null){ |
| Block block = new Block(0); |
| block.sourceStart = this.methodDeclaration.bodyStart; |
| this.add(block, 1); |
| } |
| this.methodBody.attachPendingModifiers( |
| this.pendingAnnotations, |
| this.pendingAnnotationCount, |
| this.pendingModifiers, |
| this.pendingModifersSourceStart); |
| resetPendingModifiers(); |
| return this.methodBody.add(typeDeclaration, bracketBalanceValue, true); |
| } |
| switch (TypeDeclaration.kind(typeDeclaration.modifiers)) { |
| case TypeDeclaration.INTERFACE_DECL : |
| case TypeDeclaration.ANNOTATION_TYPE_DECL : |
| resetPendingModifiers(); |
| this.updateSourceEndIfNecessary(previousAvailableLineEnd(typeDeclaration.declarationSourceStart - 1)); |
| if (this.parent == null) { |
| return this; // ignore |
| } |
| // close the constructor |
| return this.parent.add(typeDeclaration, bracketBalanceValue); |
| } |
| if (this.localTypes == null) { |
| this.localTypes = new RecoveredType[5]; |
| this.localTypeCount = 0; |
| } else { |
| if (this.localTypeCount == this.localTypes.length) { |
| System.arraycopy( |
| this.localTypes, |
| 0, |
| (this.localTypes = new RecoveredType[2 * this.localTypeCount]), |
| 0, |
| this.localTypeCount); |
| } |
| } |
| RecoveredType element = new RecoveredType(typeDeclaration, this, bracketBalanceValue); |
| this.localTypes[this.localTypeCount++] = element; |
| |
| if(this.pendingAnnotationCount > 0) { |
| element.attach( |
| this.pendingAnnotations, |
| this.pendingAnnotationCount, |
| this.pendingModifiers, |
| this.pendingModifersSourceStart); |
| } |
| resetPendingModifiers(); |
| |
| /* consider that if the opening brace was not found, it is there */ |
| if (!this.foundOpeningBrace){ |
| this.foundOpeningBrace = true; |
| this.bracketBalance++; |
| } |
| return element; |
| } |
| public boolean bodyStartsAtHeaderEnd(){ |
| return this.methodDeclaration.bodyStart == this.methodDeclaration.sourceEnd+1; |
| } |
| /* |
| * Answer the associated parsed structure |
| */ |
| public ASTNode parseTree(){ |
| return this.methodDeclaration; |
| } |
| public void resetPendingModifiers() { |
| this.pendingAnnotations = null; |
| this.pendingAnnotationCount = 0; |
| this.pendingModifiers = 0; |
| this.pendingModifersSourceStart = -1; |
| } |
| /* |
| * 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.annotations != null) { |
| for (int i = 0; i < this.annotationCount; i++) { |
| result.append("\n"); //$NON-NLS-1$ |
| result.append(this.annotations[i].toString(tab + 1)); |
| } |
| } |
| 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(int depth, Set knownTypes){ |
| /* update annotations */ |
| if (this.modifiers != 0) { |
| this.methodDeclaration.modifiers |= this.modifiers; |
| if (this.modifiersStart < this.methodDeclaration.declarationSourceStart) { |
| this.methodDeclaration.declarationSourceStart = this.modifiersStart; |
| } |
| } |
| /* update annotations */ |
| if (this.annotationCount > 0){ |
| int existingCount = this.methodDeclaration.annotations == null ? 0 : this.methodDeclaration.annotations.length; |
| Annotation[] annotationReferences = new Annotation[existingCount + this.annotationCount]; |
| if (existingCount > 0){ |
| System.arraycopy(this.methodDeclaration.annotations, 0, annotationReferences, this.annotationCount, existingCount); |
| } |
| for (int i = 0; i < this.annotationCount; i++){ |
| annotationReferences[i] = this.annotations[i].updatedAnnotationReference(); |
| } |
| this.methodDeclaration.annotations = annotationReferences; |
| |
| int start = this.annotations[0].annotation.sourceStart; |
| if (start < this.methodDeclaration.declarationSourceStart) { |
| this.methodDeclaration.declarationSourceStart = start; |
| } |
| } |
| |
| if (this.methodBody != null){ |
| Block block = this.methodBody.updatedBlock(depth, knownTypes); |
| if (block != null){ |
| this.methodDeclaration.statements = block.statements; |
| //{ObjectTeams: new flag: |
| this.methodDeclaration.hasParsedStatements = true; |
| // SH} |
| |
| if (this.methodDeclaration.declarationSourceEnd == 0) { |
| this.methodDeclaration.declarationSourceEnd = block.sourceEnd; |
| this.methodDeclaration.bodyEnd = block.sourceEnd; |
| } |
| |
| /* first statement might be an explict constructor call destinated to a special slot */ |
| if (this.methodDeclaration.isConstructor()) { |
| ConstructorDeclaration constructor = (ConstructorDeclaration)this.methodDeclaration; |
| if (this.methodDeclaration.statements != null |
| && this.methodDeclaration.statements[0] instanceof ExplicitConstructorCall){ |
| constructor.constructorCall = (ExplicitConstructorCall)this.methodDeclaration.statements[0]; |
| int length = this.methodDeclaration.statements.length; |
| System.arraycopy( |
| this.methodDeclaration.statements, |
| 1, |
| (this.methodDeclaration.statements = new Statement[length-1]), |
| 0, |
| length-1); |
| } |
| if (constructor.constructorCall == null){ // add implicit constructor call |
| constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); |
| } |
| } |
| } |
| } else { |
| if (this.methodDeclaration.declarationSourceEnd == 0) { |
| if (this.methodDeclaration.sourceEnd + 1 == this.methodDeclaration.bodyStart) { |
| // right brace is missing |
| this.methodDeclaration.declarationSourceEnd = this.methodDeclaration.sourceEnd; |
| this.methodDeclaration.bodyStart = this.methodDeclaration.sourceEnd; |
| this.methodDeclaration.bodyEnd = this.methodDeclaration.sourceEnd; |
| } else { |
| this.methodDeclaration.declarationSourceEnd = this.methodDeclaration.bodyStart; |
| this.methodDeclaration.bodyEnd = this.methodDeclaration.bodyStart; |
| } |
| } |
| } |
| //{ObjectTeams: ensure signature has taken place apropriately: |
| if (this.methodDeclaration.isCallin() && !MethodSignatureEnhancer.isEnhanced(this.methodDeclaration)) { |
| AstGenerator gen = new AstGenerator(this.methodDeclaration.sourceStart, this.methodDeclaration.sourceEnd); |
| this.methodDeclaration.arguments = MethodSignatureEnhancer.enhanceArguments(this.methodDeclaration.arguments, new char[0], /*isWrapper*/false, gen); |
| } |
| // SH} |
| if (this.localTypeCount > 0) this.methodDeclaration.bits |= ASTNode.HasLocalType; |
| return this.methodDeclaration; |
| } |
| /* |
| * Update the corresponding parse node from parser state which |
| * is about to disappear because of restarting recovery |
| */ |
| public void updateFromParserState(){ |
| // if parent is null then recovery already occured in diet parser. |
| if(bodyStartsAtHeaderEnd() && this.parent != null){ |
| Parser parser = 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 (this.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 |
| |
| // remove unfinished annotation nodes |
| MemberValuePair[] memberValuePairs = null; |
| while (argLength > 0 && parser.astStack[parser.astPtr] instanceof MemberValuePair) { |
| System.arraycopy(parser.astStack, argStart, memberValuePairs = new MemberValuePair[argLength], 0, argLength); |
| parser.astLengthPtr--; |
| parser.astPtr -= argLength; |
| |
| argLength = parser.astLengthStack[parser.astLengthPtr]; |
| argStart = parser.astPtr - argLength + 1; |
| needUpdateRParenPos = true; |
| } |
| |
| // to compute bodyStart, and thus used to set next checkpoint. |
| int count; |
| for (count = 0; count < argLength; count++){ |
| ASTNode aNode = parser.astStack[argStart+count]; |
| if(aNode instanceof Argument) { |
| Argument argument = (Argument)aNode; |
| /* cannot be an argument if non final */ |
| char[][] argTypeName = argument.type.getTypeName(); |
| if ((argument.modifiers & ~ClassFileConstants.AccFinal) != 0 |
| || (argTypeName.length == 1 |
| && CharOperation.equals(argTypeName[0], TypeBinding.VOID.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; |
| } else { |
| parser.astLengthStack[parser.astLengthPtr] = count; |
| parser.astPtr = argStart+count-1; |
| parser.listLength = count; |
| parser.currentToken = 0; |
| break; |
| } |
| } |
| 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.consumeMethodHeaderRightParen(); |
| /* 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 */ |
| this.methodDeclaration.sourceEnd = this.methodDeclaration.arguments[this.methodDeclaration.arguments.length-1].sourceEnd; |
| this.methodDeclaration.bodyStart = this.methodDeclaration.sourceEnd+1; |
| parser.lastCheckPoint = this.methodDeclaration.bodyStart; |
| } |
| } |
| } |
| |
| if(memberValuePairs != null) { |
| System.arraycopy(memberValuePairs, 0, parser.astStack, parser.astPtr + 1, memberValuePairs.length); |
| parser.astPtr += memberValuePairs.length; |
| parser.astLengthStack[++parser.astLengthPtr] = memberValuePairs.length; |
| } |
| } |
| } |
| } |
| } |
| public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ |
| if(this.methodDeclaration.isAnnotationMethod()) { |
| this.updateSourceEndIfNecessary(braceStart, braceEnd); |
| if(!this.foundOpeningBrace && this.parent != null) { |
| return this.parent.updateOnClosingBrace(braceStart, braceEnd); |
| } |
| return this; |
| } |
| if(this.parent != null && this.parent instanceof RecoveredType) { |
| int mods = ((RecoveredType)this.parent).typeDeclaration.modifiers; |
| if (TypeDeclaration.kind(mods) == TypeDeclaration.INTERFACE_DECL) { |
| if (!this.foundOpeningBrace) { |
| this.updateSourceEndIfNecessary(braceStart - 1, braceStart - 1); |
| return this.parent.updateOnClosingBrace(braceStart, braceEnd); |
| } |
| } |
| } |
| return super.updateOnClosingBrace(braceStart, braceEnd); |
| } |
| /* |
| * 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 (this.bracketBalance == 0){ |
| /* |
| if (parser.scanner.searchLineNumber(methodDeclaration.sourceEnd) |
| != parser.scanner.searchLineNumber(braceEnd)){ |
| */ |
| switch(parser().lastIgnoredToken){ |
| case -1 : |
| case TokenNamethrows : |
| break; |
| default: |
| this.foundOpeningBrace = true; |
| this.bracketBalance = 1; // pretend the brace was already there |
| } |
| } |
| return super.updateOnOpeningBrace(braceStart, braceEnd); |
| } |
| public void updateParseTree(){ |
| updatedMethodDeclaration(0, new HashSet()); |
| } |
| /* |
| * 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; |
| } |
| } |
| } |
| public RecoveredElement addAnnotationName(int identifierPtr, int identifierLengthPtr, int annotationStart, int bracketBalanceValue) { |
| if (this.pendingAnnotations == null) { |
| this.pendingAnnotations = new RecoveredAnnotation[5]; |
| this.pendingAnnotationCount = 0; |
| } else { |
| if (this.pendingAnnotationCount == this.pendingAnnotations.length) { |
| System.arraycopy( |
| this.pendingAnnotations, |
| 0, |
| (this.pendingAnnotations = new RecoveredAnnotation[2 * this.pendingAnnotationCount]), |
| 0, |
| this.pendingAnnotationCount); |
| } |
| } |
| |
| RecoveredAnnotation element = new RecoveredAnnotation(identifierPtr, identifierLengthPtr, annotationStart, this, bracketBalanceValue); |
| |
| this.pendingAnnotations[this.pendingAnnotationCount++] = element; |
| |
| return element; |
| } |
| public void addModifier(int flag, int modifiersSourceStart) { |
| this.pendingModifiers |= flag; |
| |
| if (this.pendingModifersSourceStart < 0) { |
| this.pendingModifersSourceStart = modifiersSourceStart; |
| } |
| } |
| void attach(TypeParameter[] parameters, int startPos) { |
| if(this.methodDeclaration.modifiers != ClassFileConstants.AccDefault) return; |
| |
| int lastParameterEnd = parameters[parameters.length - 1].sourceEnd; |
| |
| Parser parser = parser(); |
| Scanner scanner = parser.scanner; |
| if(Util.getLineNumber(this.methodDeclaration.declarationSourceStart, scanner.lineEnds, 0, scanner.linePtr) |
| != Util.getLineNumber(lastParameterEnd, scanner.lineEnds, 0, scanner.linePtr)) return; |
| |
| if(parser.modifiersSourceStart > lastParameterEnd |
| && parser.modifiersSourceStart < this.methodDeclaration.declarationSourceStart) return; |
| |
| if (this.methodDeclaration instanceof MethodDeclaration) { |
| ((MethodDeclaration)this.methodDeclaration).typeParameters = parameters; |
| this.methodDeclaration.declarationSourceStart = startPos; |
| } else if (this.methodDeclaration instanceof ConstructorDeclaration){ |
| ((ConstructorDeclaration)this.methodDeclaration).typeParameters = parameters; |
| this.methodDeclaration.declarationSourceStart = startPos; |
| } |
| } |
| public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) { |
| if (annotCount > 0) { |
| Annotation[] existingAnnotations = this.methodDeclaration.annotations; |
| if (existingAnnotations != null) { |
| this.annotations = new RecoveredAnnotation[annotCount]; |
| this.annotationCount = 0; |
| next : for (int i = 0; i < annotCount; i++) { |
| for (int j = 0; j < existingAnnotations.length; j++) { |
| if (annots[i].annotation == existingAnnotations[j]) continue next; |
| } |
| this.annotations[this.annotationCount++] = annots[i]; |
| } |
| } else { |
| this.annotations = annots; |
| this.annotationCount = annotCount; |
| } |
| } |
| |
| if (mods != 0) { |
| this.modifiers = mods; |
| this.modifiersStart = modsSourceStart; |
| } |
| } |
| //{ObjectTeams: remove a method which is converted to a MethodSpecLong |
| public RecoveredElement remove() { |
| RecoveredType type = enclosingType(); |
| if (type == null) |
| return this; // no chance, leave current currentElement. |
| type.removeCurrentMethod(); |
| return type; |
| } |
| // SH} |
| |
| } |