first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / SourceElementParser.java
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 (file)
index 0000000..9c346d5
--- /dev/null
@@ -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 <position>, or the end position of a comment line 
+ * immediately following the <position> (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<length;i++) {
+                       AstNode node = nodes[i];
+                       if (node instanceof ImportReference) {
+                               ImportReference importRef = (ImportReference)node;
+                               if (node == parsedUnit.currentPackage) {
+                                       notifySourceElementRequestor(importRef, true);
+                               } else {
+                                       notifySourceElementRequestor(importRef, false);
+                               }
+                       } else { // instanceof TypeDeclaration
+                               notifySourceElementRequestor((TypeDeclaration)node, sourceType == null);
+                       }
+               }
+       }
+       
+       if (sourceType == null){
+               if (isInRange) {
+                       requestor.exitCompilationUnit(parsedUnit.sourceEnd);
+               }
+       }
+}
+
+private void notifyAllUnknownReferences() {
+       for (int i = 0, max = this.unknownRefsCounter; i < max; i++) {
+               NameReference nameRef = this.unknownRefs[i];
+               if ((nameRef.bits & BindingIds.VARIABLE) != 0) {
+                       if ((nameRef.bits & BindingIds.TYPE) == 0) { 
+                               // variable but not type
+                               if (nameRef instanceof SingleNameReference) { 
+                                       // local var or field
+                                       requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
+                               } else {
+                                       // QualifiedNameReference
+                                       // The last token is a field reference and the previous tokens are a type/variable references
+                                       char[][] tokens = ((QualifiedNameReference) nameRef).tokens;
+                                       int tokensLength = tokens.length;
+                                       requestor.acceptFieldReference(tokens[tokensLength - 1], nameRef.sourceEnd - tokens[tokensLength - 1].length + 1);
+                                       char[][] typeRef = new char[tokensLength - 1][];
+                                       System.arraycopy(tokens, 0, typeRef, 0, tokensLength - 1);
+                                       requestor.acceptUnknownReference(typeRef, nameRef.sourceStart, nameRef.sourceEnd - tokens[tokensLength - 1].length);
+                               }
+                       } else {
+                               // variable or type
+                               if (nameRef instanceof SingleNameReference) {
+                                       requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
+                               } else {
+                                       //QualifiedNameReference
+                                       requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
+                               }
+                       }
+               } else if ((nameRef.bits & BindingIds.TYPE) != 0) {
+                       if (nameRef instanceof SingleNameReference) {
+                               requestor.acceptTypeReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
+                       } else {
+                               // it is a QualifiedNameReference
+                               requestor.acceptTypeReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
+                       }
+               }
+       }
+}
+/*
+ * Update the bodyStart of the corresponding parse node
+ */
+public void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration) {
+
+       // range check
+       boolean isInRange = 
+                               scanner.initialPosition <= methodDeclaration.declarationSourceStart
+                               && scanner.eofPosition >= 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);
+}
+
+}