| /******************************************************************************* |
| * Copyright (c) 2008 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 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.parser; |
| |
| import org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.eclipse.jdt.internal.compiler.ast.Annotation; |
| import org.eclipse.jdt.internal.compiler.ast.Expression; |
| import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation; |
| import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; |
| import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation; |
| import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; |
| import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| |
| public class RecoveredAnnotation extends RecoveredElement { |
| public static final int MARKER = 0; |
| public static final int NORMAL = 1; |
| public static final int SINGLE_MEMBER = 2; |
| |
| private int kind; |
| private int identifierPtr; |
| private int identifierLengthPtr; |
| private int sourceStart; |
| public boolean hasPendingMemberValueName; |
| public int memberValuPairEqualEnd = -1; |
| public Annotation annotation; |
| |
| public RecoveredAnnotation(int identifierPtr, int identifierLengthPtr, int sourceStart, RecoveredElement parent, int bracketBalance) { |
| super(parent, bracketBalance); |
| this.kind = MARKER; |
| this.identifierPtr = identifierPtr; |
| this.identifierLengthPtr = identifierLengthPtr; |
| this.sourceStart = sourceStart; |
| } |
| |
| public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) { |
| if (this.annotation == null && (typeDeclaration.bits & ASTNode.IsAnonymousType) != 0){ |
| // ignore anonymous type in annotations when annotation isn't fully recovered |
| return this; |
| } |
| return super.add(typeDeclaration, bracketBalanceValue); |
| } |
| |
| public RecoveredElement addAnnotationName(int identPtr, int identLengthPtr, int annotationStart, int bracketBalanceValue) { |
| |
| RecoveredAnnotation element = new RecoveredAnnotation(identPtr, identLengthPtr, annotationStart, this, bracketBalanceValue); |
| |
| return element; |
| } |
| |
| public RecoveredElement addAnnotation(Annotation annot, int index) { |
| this.annotation = annot; |
| |
| if (this.parent != null) return this.parent; |
| return this; |
| } |
| |
| public void updateFromParserState() { |
| Parser parser = parser(); |
| |
| if (this.annotation == null && this.identifierPtr <= parser.identifierPtr) { |
| Annotation annot = null; |
| |
| boolean needUpdateRParenPos = false; |
| |
| MemberValuePair pendingMemberValueName = null; |
| if (this.hasPendingMemberValueName && this.identifierPtr < parser.identifierPtr) { |
| char[] memberValueName = parser.identifierStack[this.identifierPtr + 1]; |
| |
| long pos = parser.identifierPositionStack[this.identifierPtr + 1]; |
| int start = (int) (pos >>> 32); |
| int end = (int)pos; |
| int valueEnd = this.memberValuPairEqualEnd > -1 ? this.memberValuPairEqualEnd : end; |
| |
| SingleNameReference fakeExpression = new SingleNameReference(RecoveryScanner.FAKE_IDENTIFIER, (((long) valueEnd + 1) << 32) + (valueEnd)); |
| pendingMemberValueName = new MemberValuePair(memberValueName, start, end, fakeExpression); |
| } |
| parser.identifierPtr = this.identifierPtr; |
| parser.identifierLengthPtr = this.identifierLengthPtr; |
| TypeReference typeReference = parser.getAnnotationType(); |
| |
| switch (this.kind) { |
| case NORMAL: |
| if (parser.astPtr > -1 && parser.astStack[parser.astPtr] instanceof MemberValuePair) { |
| MemberValuePair[] memberValuePairs = null; |
| |
| int argLength = parser.astLengthStack[parser.astLengthPtr]; |
| int argStart = parser.astPtr - argLength + 1; |
| |
| if (argLength > 0) { |
| int annotationEnd; |
| if (pendingMemberValueName != null) { |
| memberValuePairs = new MemberValuePair[argLength + 1]; |
| |
| System.arraycopy(parser.astStack, argStart, memberValuePairs, 0, argLength); |
| parser.astLengthPtr--; |
| parser.astPtr -= argLength; |
| |
| memberValuePairs[argLength] = pendingMemberValueName; |
| |
| annotationEnd = pendingMemberValueName.sourceEnd; |
| } else { |
| memberValuePairs = new MemberValuePair[argLength]; |
| |
| System.arraycopy(parser.astStack, argStart, memberValuePairs, 0, argLength); |
| parser.astLengthPtr--; |
| parser.astPtr -= argLength; |
| |
| MemberValuePair lastMemberValuePair = memberValuePairs[memberValuePairs.length - 1]; |
| |
| annotationEnd = |
| lastMemberValuePair.value != null |
| ? lastMemberValuePair.value instanceof Annotation |
| ? ((Annotation)lastMemberValuePair.value).declarationSourceEnd |
| : lastMemberValuePair.value.sourceEnd |
| : lastMemberValuePair.sourceEnd; |
| } |
| |
| NormalAnnotation normalAnnotation = new NormalAnnotation(typeReference, this.sourceStart); |
| normalAnnotation.memberValuePairs = memberValuePairs; |
| normalAnnotation.declarationSourceEnd = annotationEnd; |
| normalAnnotation.bits |= ASTNode.IsRecovered; |
| |
| annot = normalAnnotation; |
| |
| needUpdateRParenPos = true; |
| } |
| } |
| |
| |
| break; |
| case SINGLE_MEMBER: |
| if (parser.expressionPtr > -1) { |
| Expression memberValue = parser.expressionStack[parser.expressionPtr--]; |
| |
| SingleMemberAnnotation singleMemberAnnotation = new SingleMemberAnnotation(typeReference, this.sourceStart); |
| singleMemberAnnotation.memberValue = memberValue; |
| singleMemberAnnotation.declarationSourceEnd = memberValue.sourceEnd; |
| singleMemberAnnotation.bits |= ASTNode.IsRecovered; |
| |
| annot = singleMemberAnnotation; |
| |
| needUpdateRParenPos = true; |
| } |
| break; |
| } |
| |
| if (!needUpdateRParenPos) { |
| if (pendingMemberValueName != null) { |
| NormalAnnotation normalAnnotation = new NormalAnnotation(typeReference, this.sourceStart); |
| normalAnnotation.memberValuePairs = new MemberValuePair[]{pendingMemberValueName}; |
| normalAnnotation.declarationSourceEnd = pendingMemberValueName.value.sourceEnd; |
| normalAnnotation.bits |= ASTNode.IsRecovered; |
| |
| annot = normalAnnotation; |
| } else { |
| MarkerAnnotation markerAnnotation = new MarkerAnnotation(typeReference, this.sourceStart); |
| markerAnnotation.declarationSourceEnd = markerAnnotation.sourceEnd; |
| markerAnnotation.bits |= ASTNode.IsRecovered; |
| |
| annot = markerAnnotation; |
| } |
| } |
| |
| parser.currentElement = addAnnotation(annot, this.identifierPtr); |
| parser.annotationRecoveryCheckPoint(annot.sourceStart, annot.declarationSourceEnd); |
| if (this.parent != null) { |
| |
| this.parent.updateFromParserState(); |
| } |
| } |
| } |
| |
| public ASTNode parseTree() { |
| return this.annotation; |
| } |
| |
| public void resetPendingModifiers() { |
| if (this.parent != null) this.parent.resetPendingModifiers(); |
| } |
| |
| public void setKind(int kind) { |
| this.kind = kind; |
| } |
| |
| public int sourceEnd() { |
| if (this.annotation == null) { |
| Parser parser = parser(); |
| if (this.identifierPtr < parser.identifierPositionStack.length) { |
| return (int) parser.identifierPositionStack[this.identifierPtr]; |
| } else { |
| return this.sourceStart; |
| } |
| } |
| return this.annotation.declarationSourceEnd; |
| } |
| |
| public String toString(int tab) { |
| if (this.annotation != null) { |
| return tabString(tab) + "Recovered annotation:\n" + this.annotation.print(tab + 1, new StringBuffer(10)); //$NON-NLS-1$ |
| } else { |
| return tabString(tab) + "Recovered annotation: identiferPtr=" + this.identifierPtr + " identiferlengthPtr=" + this.identifierLengthPtr + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| |
| public Annotation updatedAnnotationReference() { |
| return this.annotation; |
| } |
| |
| public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){ |
| if (this.bracketBalance > 0){ // was an member value array initializer |
| this.bracketBalance--; |
| return this; |
| } |
| if (this.parent != null){ |
| return this.parent.updateOnClosingBrace(braceStart, braceEnd); |
| } |
| return this; |
| } |
| |
| public void updateParseTree() { |
| updatedAnnotationReference(); |
| } |
| } |