X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java new file mode 100644 index 0000000..9c346d5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java @@ -0,0 +1,1294 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +/** + * A source element parser extracts structural and reference information + * from a piece of source. + * + * also see @ISourceElementRequestor + * + * The structural investigation includes: + * - the package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * If reference information is requested, then all source constructs are + * investigated and type, field & method references are provided as well. + * + * Any (parsing) problem encountered is also provided. + */ + +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; + +public class SourceElementParser extends Parser { + + ISourceElementRequestor requestor; + private int fieldCount; + private int localIntPtr; + private int lastFieldEndPosition; + private ISourceType sourceType; + private boolean reportReferenceInfo; + private char[][] typeNames; + private char[][] superTypeNames; + private int nestedTypeIndex; + private static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$ + private NameReference[] unknownRefs; + private int unknownRefsCounter; + private LocalDeclarationVisitor localDeclarationVisitor = null; + private CompilerOptions options; + +/** + * An ast visitor that visits local type declarations. + */ +public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter { + public boolean visit( + AnonymousLocalTypeDeclaration anonymousTypeDeclaration, + BlockScope scope) { + notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + public boolean visit(LocalTypeDeclaration typeDeclaration, BlockScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + public boolean visit(MemberTypeDeclaration typeDeclaration, ClassScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + +} + +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory, + CompilerOptions options) { + // we want to notify all syntax error with the acceptProblem API + // To do so, we define the record method of the ProblemReporter + super(new ProblemReporter( + DefaultErrorHandlingPolicies.exitAfterAllProblems(), + options, + problemFactory) { + public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); + requestor.acceptProblem(problem); + } + }, + true, + options.assertMode); + this.requestor = requestor; + typeNames = new char[4][]; + superTypeNames = new char[4][]; + nestedTypeIndex = 0; + this.options = options; +} + +/** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */ +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory) { + this(requestor, problemFactory, new CompilerOptions()); +} + +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory, + CompilerOptions options, + boolean reportLocalDeclarations) { + this(requestor, problemFactory, options); + if (reportLocalDeclarations) { + this.localDeclarationVisitor = new LocalDeclarationVisitor(); + } +} + +public void checkAnnotation() { + int firstCommentIndex = scanner.commentPtr; + + super.checkAnnotation(); + + // modify the modifier source start to point at the first comment + if (firstCommentIndex >= 0) { + modifiersSourceStart = scanner.commentStarts[0]; + } +} + +protected void classInstanceCreation(boolean alwaysQualified) { + + boolean previousFlag = reportReferenceInfo; + reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...) + super.classInstanceCreation(alwaysQualified); + reportReferenceInfo = previousFlag; + if (reportReferenceInfo){ + AllocationExpression alloc = (AllocationExpression)expressionStack[expressionPtr]; + TypeReference typeRef = alloc.type; + requestor.acceptConstructorReference( + typeRef instanceof SingleTypeReference + ? ((SingleTypeReference) typeRef).token + : CharOperation.concatWith(alloc.type.getTypeName(), '.'), + alloc.arguments == null ? 0 : alloc.arguments.length, + alloc.sourceStart); + } +} +protected void consumeConstructorHeaderName() { + // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' + + /* recovering - might be an empty message send */ + if (currentElement != null){ + if (lastIgnoredToken == TokenNamenew){ // was an allocation expression + lastCheckPoint = scanner.startPosition; // force to restart at this exact position + restartRecovery = true; + return; + } + } + SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult); + + //name -- this is not really revelant but we do ..... + cd.selector = identifierStack[identifierPtr]; + long selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + + //modifiers + cd.declarationSourceStart = intStack[intPtr--]; + cd.modifiers = intStack[intPtr--]; + + //highlight starts at the selector starts + cd.sourceStart = (int) (selectorSourcePositions >>> 32); + cd.selectorSourceEnd = (int) selectorSourcePositions; + pushOnAstStack(cd); + + cd.sourceEnd = lParenPos; + cd.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + lastCheckPoint = cd.bodyStart; + if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT) + || cd.modifiers != 0){ + currentElement = currentElement.add(cd, 0); + lastIgnoredToken = -1; + } + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeExitVariableWithInitialization() { + // ExitVariableWithInitialization ::= $empty + // the scanner is located after the comma or the semi-colon. + // we want to include the comma or the semi-colon + super.consumeExitVariableWithInitialization(); + if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) + return; + ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +} +protected void consumeExitVariableWithoutInitialization() { + // ExitVariableWithoutInitialization ::= $empty + // do nothing by default + if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) + return; + ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + super.consumeFieldAccess(isSuperAccess); + FieldReference fr = (FieldReference) expressionStack[expressionPtr]; + if (reportReferenceInfo) { + requestor.acceptFieldReference(fr.token, fr.sourceStart); + } +} +protected void consumeMethodHeaderName() { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + long selectorSourcePositions = identifierPositionStack[identifierPtr--]; + identifierLengthPtr--; + //type + md.returnType = getTypeReference(intStack[intPtr--]); + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSourcePositions >>> 32); + md.selectorSourceEnd = (int) selectorSourcePositions; + pushOnAstStack(md); + md.sourceEnd = lParenPos; + md.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + // recovery + if (currentElement != null){ + if (currentElement instanceof RecoveredType + //|| md.modifiers != 0 + || (scanner.getLineNumber(md.returnType.sourceStart) + == scanner.getLineNumber(md.sourceStart))){ + lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } else { + lastCheckPoint = md.sourceStart; + restartRecovery = true; + } + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationName() { + // MethodInvocation ::= Name '(' ArgumentListopt ')' + + // when the name is only an identifier...we have a message send to "this" (implicit) + super.consumeMethodInvocationName(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationPrimary() { + super.consumeMethodInvocationPrimary(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +/** + * + * INTERNAL USE-ONLY + */ +protected void consumeMethodInvocationSuper() { + // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' + super.consumeMethodInvocationSuper(); + MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; + Expression[] args = messageSend.arguments; + if (reportReferenceInfo) { + requestor.acceptMethodReference( + messageSend.selector, + args == null ? 0 : args.length, + (int)(messageSend.nameSourcePosition >>> 32)); + } +} +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + super.consumeSingleTypeImportDeclarationName(); + ImportReference impt = (ImportReference)astStack[astPtr]; + if (reportReferenceInfo) { + requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd); + } +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + super.consumeTypeImportOnDemandDeclarationName(); + ImportReference impt = (ImportReference)astStack[astPtr]; + if (reportReferenceInfo) { + requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd); + } +} +protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd); +} +protected CompilationUnitDeclaration endParse(int act) { + if (sourceType != null) { + if (sourceType.isInterface()) { + consumeInterfaceDeclaration(); + } else { + consumeClassDeclaration(); + } + } + if (compilationUnit != null) { + CompilationUnitDeclaration result = super.endParse(act); + return result; + } else { + return null; + } +} +/* + * Flush annotations defined prior to a given positions. + * + * Note: annotations are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ + +public int flushAnnotationsDefinedPriorTo(int position) { + + return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position); +} +public TypeReference getTypeReference(int dim) { + /* build a Reference on a variable that may be qualified or not + * This variable is a type reference and dim will be its dimensions + */ + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + if (dim == 0) { + SingleTypeReference ref = + new SingleTypeReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.token, ref.sourceStart); + } + return ref; + } else { + ArrayTypeReference ref = + new ArrayTypeReference( + identifierStack[identifierPtr], + dim, + identifierPositionStack[identifierPtr--]); + ref.sourceEnd = endPosition; + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.token, ref.sourceStart); + } + return ref; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + TypeReference ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[intPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[intPtr--]; + } else { + intPtr--; // no need to use this position as it is an array + ref.sourceEnd = endPosition; + } + if (reportReferenceInfo){ + requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd); + } + return ref; + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions); + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); + } + return ref; + } else { + ArrayQualifiedTypeReference ref = + new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + if (reportReferenceInfo) { + requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); + } + return ref; + } + } + } +} +public NameReference getUnspecifiedReference() { + /* build a (unspecified) NameReference which may be qualified*/ + + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + SingleNameReference ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } else { + //Qualified variable reference + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + QualifiedNameReference ref = + new QualifiedNameReference( + tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } +} +public NameReference getUnspecifiedReferenceOptimized() { + /* build a (unspecified) NameReference which may be qualified + The optimization occurs for qualified reference while we are + certain in this case the last item of the qualified name is + a field access. This optimization is IMPORTANT while it results + that when a NameReference is build, the type checker should always + look for that it is not a type reference */ + + int length; + if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { + // single variable reference + SingleNameReference ref = + new SingleNameReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; + } + + //Qualified-variable-reference + //In fact it is variable-reference DOT field-ref , but it would result in a type + //conflict tha can be only reduce by making a superclass (or inetrface ) between + //nameReference and FiledReference or putting FieldReference under NameReference + //or else..........This optimisation is not really relevant so just leave as it is + + char[][] tokens = new char[length][]; + identifierPtr -= length; + System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); + QualifiedNameReference ref = + new QualifiedNameReference( + tokens, + (int) (identifierPositionStack[identifierPtr + 1] >> 32), + // sourceStart + (int) identifierPositionStack[identifierPtr + length]); // sourceEnd + ref.bits &= ~AstNode.RestrictiveFlagMASK; + ref.bits |= LOCAL | FIELD; + if (reportReferenceInfo) { + this.addUnknownRef(ref); + } + return ref; +} +/** + * + * INTERNAL USE-ONLY + */ +private boolean isLocalDeclaration() { + int nestedDepth = nestedType; + while (nestedDepth >= 0) { + if (nestedMethod[nestedDepth] != 0) { + return true; + } + nestedDepth--; + } + return false; +} +/* + * Update the bodyStart of the corresponding parse node + */ +public void notifySourceElementRequestor(CompilationUnitDeclaration parsedUnit) { + if (parsedUnit == null) { + // when we parse a single type member declaration the compilation unit is null, but we still + // want to be able to notify the requestor on the created ast node + if (astStack[0] instanceof AbstractMethodDeclaration) { + notifySourceElementRequestor((AbstractMethodDeclaration) astStack[0]); + return; + } + return; + } + // range check + boolean isInRange = + scanner.initialPosition <= parsedUnit.sourceStart + && scanner.eofPosition >= parsedUnit.sourceEnd; + + if (reportReferenceInfo) { + notifyAllUnknownReferences(); + } + // collect the top level ast nodes + int length = 0; + AstNode[] nodes = null; + if (sourceType == null){ + if (isInRange) { + requestor.enterCompilationUnit(); + } + ImportReference currentPackage = parsedUnit.currentPackage; + ImportReference[] imports = parsedUnit.imports; + TypeDeclaration[] types = parsedUnit.types; + length = + (currentPackage == null ? 0 : 1) + + (imports == null ? 0 : imports.length) + + (types == null ? 0 : types.length); + nodes = new AstNode[length]; + int index = 0; + if (currentPackage != null) { + nodes[index++] = currentPackage; + } + if (imports != null) { + for (int i = 0, max = imports.length; i < max; i++) { + nodes[index++] = imports[i]; + } + } + if (types != null) { + for (int i = 0, max = types.length; i < max; i++) { + nodes[index++] = types[i]; + } + } + } else { + TypeDeclaration[] types = parsedUnit.types; + if (types != null) { + length = types.length; + nodes = new AstNode[length]; + for (int i = 0, max = types.length; i < max; i++) { + nodes[i] = types[i]; + } + } + } + + // notify the nodes in the syntactical order + if (nodes != null && length > 0) { + quickSort(nodes, 0, length-1); + for (int i=0;i= methodDeclaration.declarationSourceEnd; + + if (methodDeclaration.isClinit()) { + this.visitIfNeeded(methodDeclaration); + return; + } + + if (methodDeclaration.isDefaultConstructor()) { + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + return; + } + char[][] argumentTypes = null; + char[][] argumentNames = null; + Argument[] arguments = methodDeclaration.arguments; + if (arguments != null) { + int argumentLength = arguments.length; + argumentTypes = new char[argumentLength][]; + argumentNames = new char[argumentLength][]; + for (int i = 0; i < argumentLength; i++) { + argumentTypes[i] = returnTypeName(arguments[i].type); + argumentNames[i] = arguments[i].name; + } + } + char[][] thrownExceptionTypes = null; + TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; + if (thrownExceptions != null) { + int thrownExceptionLength = thrownExceptions.length; + thrownExceptionTypes = new char[thrownExceptionLength][]; + for (int i = 0; i < thrownExceptionLength; i++) { + thrownExceptionTypes[i] = + CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.'); + } + } + // by default no selector end position + int selectorSourceEnd = -1; + if (methodDeclaration.isConstructor()) { + if (methodDeclaration instanceof SourceConstructorDeclaration) { + selectorSourceEnd = + ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd; + } + if (isInRange){ + requestor.enterConstructor( + methodDeclaration.declarationSourceStart, + methodDeclaration.modifiers, + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + this.visitIfNeeded(methodDeclaration); + if (isInRange){ + requestor.exitConstructor(methodDeclaration.declarationSourceEnd); + } + return; + } + if (methodDeclaration instanceof SourceMethodDeclaration) { + selectorSourceEnd = + ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd; + } + if (isInRange){ + requestor.enterMethod( + methodDeclaration.declarationSourceStart, + methodDeclaration.modifiers & AccJustFlag, + returnTypeName(((MethodDeclaration) methodDeclaration).returnType), + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + this.visitIfNeeded(methodDeclaration); + + if (isInRange){ + requestor.exitMethod(methodDeclaration.declarationSourceEnd); + } +} +/* +* Update the bodyStart of the corresponding parse node +*/ +public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) { + + // range check + boolean isInRange = + scanner.initialPosition <= fieldDeclaration.declarationSourceStart + && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd; + + if (fieldDeclaration.isField()) { + int fieldEndPosition = fieldDeclaration.declarationSourceEnd; + if (fieldDeclaration instanceof SourceFieldDeclaration) { + fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition; + if (fieldEndPosition == 0) { + // use the declaration source end by default + fieldEndPosition = fieldDeclaration.declarationSourceEnd; + } + } + if (isInRange) { + requestor.enterField( + fieldDeclaration.declarationSourceStart, + fieldDeclaration.modifiers & AccJustFlag, + returnTypeName(fieldDeclaration.type), + fieldDeclaration.name, + fieldDeclaration.sourceStart, + fieldDeclaration.sourceEnd); + } + this.visitIfNeeded(fieldDeclaration); + if (isInRange){ + requestor.exitField(fieldEndPosition); + } + + } else { + if (isInRange){ + requestor.enterInitializer( + fieldDeclaration.declarationSourceStart, + fieldDeclaration.modifiers); + } + this.visitIfNeeded((Initializer)fieldDeclaration); + if (isInRange){ + requestor.exitInitializer(fieldDeclaration.declarationSourceEnd); + } + } +} +public void notifySourceElementRequestor( + ImportReference importReference, + boolean isPackage) { + if (isPackage) { + requestor.acceptPackage( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + CharOperation.concatWith(importReference.getImportName(), '.')); + } else { + requestor.acceptImport( + importReference.declarationSourceStart, + importReference.declarationSourceEnd, + CharOperation.concatWith(importReference.getImportName(), '.'), + importReference.onDemand); + } +} +public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) { + + // range check + boolean isInRange = + scanner.initialPosition <= typeDeclaration.declarationSourceStart + && scanner.eofPosition >= typeDeclaration.declarationSourceEnd; + + FieldDeclaration[] fields = typeDeclaration.fields; + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes; + int fieldCount = fields == null ? 0 : fields.length; + int methodCount = methods == null ? 0 : methods.length; + int memberTypeCount = memberTypes == null ? 0 : memberTypes.length; + int fieldIndex = 0; + int methodIndex = 0; + int memberTypeIndex = 0; + boolean isInterface = typeDeclaration.isInterface(); + + if (notifyTypePresence){ + char[][] interfaceNames = null; + int superInterfacesLength = 0; + TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + if (superInterfaces != null) { + superInterfacesLength = superInterfaces.length; + interfaceNames = new char[superInterfacesLength][]; + } else { + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) { + // see PR 3442 + QualifiedAllocationExpression alloc = ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation; + if (alloc != null && alloc.type != null) { + superInterfaces = new TypeReference[] { ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation.type}; + superInterfacesLength = 1; + interfaceNames = new char[1][]; + } + } + } + if (superInterfaces != null) { + for (int i = 0; i < superInterfacesLength; i++) { + interfaceNames[i] = + CharOperation.concatWith(superInterfaces[i].getTypeName(), '.'); + } + } + if (isInterface) { + if (isInRange){ + requestor.enterInterface( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers & AccJustFlag, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + interfaceNames); + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT; + } else { + TypeReference superclass = typeDeclaration.superclass; + if (superclass == null) { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + null, + interfaceNames); + } + } else { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + CharOperation.concatWith(superclass.getTypeName(), '.'), + interfaceNames); + } + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.'); + } + } + while ((fieldIndex < fieldCount) + || (memberTypeIndex < memberTypeCount) + || (methodIndex < methodCount)) { + FieldDeclaration nextFieldDeclaration = null; + AbstractMethodDeclaration nextMethodDeclaration = null; + TypeDeclaration nextMemberDeclaration = null; + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldIndex < fieldCount) { + nextFieldDeclaration = fields[fieldIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodIndex < methodCount) { + nextMethodDeclaration = methods[methodIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (memberTypeIndex < memberTypeCount) { + nextMemberDeclaration = memberTypes[memberTypeIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } + switch (nextDeclarationType) { + case 0 : + fieldIndex++; + notifySourceElementRequestor(nextFieldDeclaration); + break; + case 1 : + methodIndex++; + notifySourceElementRequestor(nextMethodDeclaration); + break; + case 2 : + memberTypeIndex++; + notifySourceElementRequestor(nextMemberDeclaration, true); + } + } + if (notifyTypePresence){ + if (isInRange){ + if (isInterface) { + requestor.exitInterface(typeDeclaration.declarationSourceEnd); + } else { + requestor.exitClass(typeDeclaration.declarationSourceEnd); + } + } + nestedTypeIndex--; + } +} +public void parseCompilationUnit( + ICompilationUnit unit, + int start, + int end, + boolean needReferenceInfo) { + + reportReferenceInfo = needReferenceInfo; + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + try { + diet = true; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end); + if (needReferenceInfo){ + diet = false; + this.getMethodBodies(parsedUnit); + } + this.scanner.resetTo(start, end); + notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} +public void parseCompilationUnit( + ICompilationUnit unit, + boolean needReferenceInfo) { + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + + try { +/* diet = !needReferenceInfo; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0); + parse(unit, compilationUnitResult); +*/ diet = true; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult); + int initialStart = this.scanner.initialPosition; + int initialEnd = this.scanner.eofPosition; + if (needReferenceInfo){ + diet = false; + this.getMethodBodies(parsedUnit); + } + this.scanner.resetTo(initialStart, initialEnd); + notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} +public void parseTypeMemberDeclarations( + ISourceType sourceType, + ICompilationUnit sourceUnit, + int start, + int end, + boolean needReferenceInfo) { + boolean old = diet; + if (needReferenceInfo) { + unknownRefs = new NameReference[10]; + unknownRefsCounter = 0; + } + + try { + diet = !needReferenceInfo; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = + new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration unit = + SourceTypeConverter.buildCompilationUnit( + new ISourceType[]{sourceType}, + false, + false, + problemReporter(), + compilationUnitResult); + if ((unit == null) || (unit.types == null) || (unit.types.length != 1)) + return; + this.sourceType = sourceType; + try { + /* automaton initialization */ + initialize(); + goForClassBodyDeclarations(); + /* scanner initialization */ + scanner.setSource(sourceUnit.getContents()); + scanner.resetTo(start, end); + /* unit creation */ + referenceContext = compilationUnit = unit; + /* initialize the astStacl */ + // the compilationUnitDeclaration should contain exactly one type + pushOnAstStack(unit.types[0]); + /* run automaton */ + parse(); + notifySourceElementRequestor(unit); + } finally { + unit = compilationUnit; + compilationUnit = null; // reset parser + } + } catch (AbortCompilation e) { + } finally { + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + diet = old; + } +} + +public void parseTypeMemberDeclarations( + char[] contents, + int start, + int end) { + + boolean old = diet; + + try { + diet = true; + + /* automaton initialization */ + initialize(); + goForClassBodyDeclarations(); + /* scanner initialization */ + scanner.setSource(contents); + scanner.recordLineSeparator = false; + scanner.resetTo(start, end); + + /* unit creation */ + referenceContext = null; + + /* initialize the astStacl */ + // the compilationUnitDeclaration should contain exactly one type + /* run automaton */ + parse(); + notifySourceElementRequestor((CompilationUnitDeclaration)null); + } catch (AbortCompilation e) { + } finally { + diet = old; + } +} +/** + * Sort the given ast nodes by their positions. + */ +private static void quickSort(AstNode[] sortedCollection, int left, int right) { + int original_left = left; + int original_right = right; + AstNode mid = sortedCollection[ (left + right) / 2]; + do { + while (sortedCollection[left].sourceStart < mid.sourceStart) { + left++; + } + while (mid.sourceStart < sortedCollection[right].sourceStart) { + right--; + } + if (left <= right) { + AstNode tmp = sortedCollection[left]; + sortedCollection[left] = sortedCollection[right]; + sortedCollection[right] = tmp; + left++; + right--; + } + } while (left <= right); + if (original_left < right) { + quickSort(sortedCollection, original_left, right); + } + if (left < original_right) { + quickSort(sortedCollection, left, original_right); + } +} +/* + * Answer a char array representation of the type name formatted like: + * - type name + dimensions + * Example: + * "A[][]".toCharArray() + * "java.lang.String".toCharArray() + */ +private char[] returnTypeName(TypeReference type) { + if (type == null) + return null; + int dimension = type.dimensions(); + if (dimension != 0) { + char[] dimensionsArray = new char[dimension * 2]; + for (int i = 0; i < dimension; i++) { + dimensionsArray[i * 2] = '['; + dimensionsArray[(i * 2) + 1] = ']'; + } + return CharOperation.concat( + CharOperation.concatWith(type.getTypeName(), '.'), + dimensionsArray); + } + return CharOperation.concatWith(type.getTypeName(), '.'); +} + +public void addUnknownRef(NameReference nameRef) { + if (this.unknownRefs.length == this.unknownRefsCounter) { + // resize + System.arraycopy( + this.unknownRefs, + 0, + (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]), + 0, + this.unknownRefsCounter); + } + this.unknownRefs[this.unknownRefsCounter++] = nameRef; +} +private TypeReference typeReference( + int dim, + int localIdentifierPtr, + int localIdentifierLengthPtr) { + /* build a Reference on a variable that may be qualified or not + * This variable is a type reference and dim will be its dimensions. + * We don't have any side effect on the stacks' pointers. + */ + + int length; + TypeReference ref; + if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) { + // single variable reference + if (dim == 0) { + ref = + new SingleTypeReference( + identifierStack[localIdentifierPtr], + identifierPositionStack[localIdentifierPtr--]); + } else { + ref = + new ArrayTypeReference( + identifierStack[localIdentifierPtr], + dim, + identifierPositionStack[localIdentifierPtr--]); + ref.sourceEnd = endPosition; + } + } else { + if (length < 0) { //flag for precompiled type reference on base types + ref = TypeReference.baseTypeReference(-length, dim); + ref.sourceStart = intStack[localIntPtr--]; + if (dim == 0) { + ref.sourceEnd = intStack[localIntPtr--]; + } else { + localIntPtr--; + ref.sourceEnd = endPosition; + } + } else { //Qualified variable reference + char[][] tokens = new char[length][]; + localIdentifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length); + System.arraycopy( + identifierPositionStack, + localIdentifierPtr + 1, + positions, + 0, + length); + if (dim == 0) { + ref = new QualifiedTypeReference(tokens, positions); + } else { + ref = new ArrayQualifiedTypeReference(tokens, dim, positions); + ref.sourceEnd = endPosition; + } + } + }; + return ref; +} + +private void visitIfNeeded(AbstractMethodDeclaration method) { + if (this.localDeclarationVisitor != null + && (method.bits & AstNode.HasLocalTypeMASK) != 0) { + if (method.statements != null) { + int statementsLength = method.statements.length; + for (int i = 0; i < statementsLength; i++) + method.statements[i].traverse(this.localDeclarationVisitor, method.scope); + } + } +} + +private void visitIfNeeded(FieldDeclaration field) { + if (this.localDeclarationVisitor != null + && (field.bits & AstNode.HasLocalTypeMASK) != 0) { + if (field.initialization != null) { + field.initialization.traverse(this.localDeclarationVisitor, null); + } + } +} + +private void visitIfNeeded(Initializer initializer) { + if (this.localDeclarationVisitor != null + && (initializer.bits & AstNode.HasLocalTypeMASK) != 0) { + if (initializer.block != null) { + initializer.block.traverse(this.localDeclarationVisitor, null); + } + } +} + +protected void reportSyntaxError(int act, int currentKind, int stateStackTop) { + if (compilationUnit == null) return; + super.reportSyntaxError(act, currentKind,stateStackTop); +} + +}