/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler;

import java.util.ArrayList;

import net.sourceforge.phpdt.core.compiler.CharOperation;
import net.sourceforge.phpdt.core.compiler.IProblem;
import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
import net.sourceforge.phpdt.internal.core.util.CommentRecorderParser;
import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.AnonymousLocalTypeDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.Argument;
import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.ExplicitConstructorCall;
import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.ImportReference;
import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.NameReference;
import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedAllocationExpression;
import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference;

/**
 * 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.
 */

public class SourceElementParser extends CommentRecorderParser {//extends
                                                                // UnitParser {

  ISourceElementRequestor requestor;
  int fieldCount;
  int localIntPtr;
  int lastFieldEndPosition;
  ISourceType sourceType;
  boolean reportReferenceInfo;
  char[][] typeNames;
  char[][] superTypeNames;
  int nestedTypeIndex;
  static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$
  NameReference[] unknownRefs;
  int unknownRefsCounter;
  LocalDeclarationVisitor localDeclarationVisitor = null;
  //	CompilerOptions options;

  /**
   * An ast visitor that visits local type declarations.
   */
  public class LocalDeclarationVisitor extends ASTVisitor {
  	public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
  		notifySourceElementRequestor(typeDeclaration, sourceType == null);
  		return false; // don't visit members as this was done during notifySourceElementRequestor(...)
  	}
  	public boolean visit(TypeDeclaration 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);
        if (requestor!=null) {
          requestor.acceptProblem(problem);
        }
      }
    });
    //	true);
    //	options.sourceLevel >= CompilerOptions.JDK1_4);
    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
  //	super.consumeExitVariableWithoutInitialization();
  //	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;
      ArrayList types = parsedUnit.types;
      if (types != null) {
        //		length =
        //			(currentPackage == null ? 0 : 1)
        //			+ (imports == null ? 0 : imports.length)
        //			+ (types == null ? 0 : types.length);
        //		nodes = new ASTNode[length];
        length = (imports == null ? 0 : imports.length) + types.size();
        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];
          }
        }

        for (int i = 0, max = types.size(); i < max; i++) {
          nodes[index++] = (ASTNode) types.get(i);
        }
      }
    } else {
      //		TypeDeclaration[] types = parsedUnit.types;
      ArrayList types = parsedUnit.types;
      if (types != null) {
        length = types.size();
        nodes = new ASTNode[length];
        for (int i = 0, max = types.size(); i < max; i++) {
          nodes[i] = (ASTNode) types.get(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
        if (node instanceof TypeDeclaration) {
          notifySourceElementRequestor((TypeDeclaration) node, sourceType == null);
          //				notifySourceElementRequestor((CompilationUnitDeclaration)node,
          // sourceType == null);
        }
        // jsurfer - INSERT start
        if (node instanceof AbstractMethodDeclaration) {
          notifySourceElementRequestor((AbstractMethodDeclaration) node);
        }
        //		jsurfer - INSERT end
      }
    }

    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) {
      int modifiers = methodDeclaration.modifiers;
      //		boolean deprecated = (modifiers & AccDeprecated) != 0; // remember
      // deprecation so as to not lose it below
      requestor.enterMethod(methodDeclaration.declarationSourceStart, modifiers, // deprecated
                                                                                 // ?
                                                                                 // (modifiers
                                                                                 // &
                                                                                 // AccJustFlag)
                                                                                 // |
                                                                                 // AccDeprecated
                                                                                 // :
                                                                                 // 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) {
        int modifiers = fieldDeclaration.modifiers;
        boolean deprecated = (modifiers & AccDeprecated) != 0; // remember
                                                               // deprecation so
                                                               // as to not lose
                                                               // it below
        requestor.enterField(fieldDeclaration.declarationSourceStart, deprecated
            ? (modifiers & AccJustFlag) | AccDeprecated
            : modifiers & AccJustFlag, returnTypeName(fieldDeclaration.type), fieldDeclaration.name, fieldDeclaration.sourceStart,
            fieldDeclaration.sourceEnd);
      }
      //		this.visitIfNeeded(fieldDeclaration);
      if (isInRange) {
        //			requestor.exitField(
        //				// filter out initializations that are not a constant (simple check)
        //				(fieldDeclaration.initialization == null
        //						|| fieldDeclaration.initialization instanceof ArrayInitializer
        //						|| fieldDeclaration.initialization instanceof AllocationExpression
        //						|| fieldDeclaration.initialization instanceof
        // ArrayAllocationExpression
        //						|| fieldDeclaration.initialization instanceof Assignment
        //						|| fieldDeclaration.initialization instanceof ClassLiteralAccess
        //						|| fieldDeclaration.initialization instanceof MessageSend
        //						|| fieldDeclaration.initialization instanceof ArrayReference
        //						|| fieldDeclaration.initialization instanceof ThisReference) ?
        //					-1 :
        //					fieldDeclaration.initialization.sourceStart,
        //				fieldEndPosition,
        //				fieldDeclaration.declarationSourceEnd);
        requestor.exitField(
        // filter out initializations that are not a constant (simple check)
            -1, fieldEndPosition, fieldDeclaration.declarationSourceEnd);
      }

    } 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,
  			importReference.getIncludeName(), //CharOperation.concatWith(importReference.getImportName(), '.'),
  			importReference.onDemand);
//  	}
  }
  public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) {
    //// public void notifySourceElementRequestor(ASTNode typeDeclaration,
    // boolean notifyTypePresence) {

    // range check
    boolean isInRange = scanner.initialPosition <= typeDeclaration.declarationSourceStart
        && scanner.eofPosition >= typeDeclaration.declarationSourceEnd;

    FieldDeclaration[] fields = typeDeclaration.fields;
    AbstractMethodDeclaration[] methods = typeDeclaration.methods;
    TypeDeclaration[] 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) {
          int modifiers = typeDeclaration.modifiers;
          boolean deprecated = false; //(modifiers & AccDeprecated) != 0; //
                                      // remember deprecation so as to not lose
                                      // it below
          requestor.enterInterface(typeDeclaration.declarationSourceStart, modifiers, //deprecated
                                                                                      // ?
                                                                                      // (modifiers
                                                                                      // &
                                                                                      // AccJustFlag)
                                                                                      // |
                                                                                      // AccDeprecated
                                                                                      // :
                                                                                      // 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, 10); //this.options.maxProblemsPerUnit);
      CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end);
      //		if (scanner.recordLineSeparator) {
      //			requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
      //		}
      //		if (this.localDeclarationVisitor != null || needReferenceInfo){
      //			diet = false;
      //			this.getMethodBodies(parsedUnit);
      //		}
      //		this.scanner.resetTo(start, end);
      //		notifySourceElementRequestor(parsedUnit);
    } catch (AbortCompilation e) {
    } finally {
      //		diet = old;
    }
  }
  public CompilationUnitDeclaration parseCompilationUnit(ICompilationUnit unit, boolean fullParse) {

    //		boolean old = diet;
    //		if (fullParse) {
    //			unknownRefs = new NameReference[10];
    //			unknownRefsCounter = 0;
    //		}

    try {
      //			diet = true;
      this.reportReferenceInfo = fullParse;
      CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
      CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, false);
      if (scanner.recordLineSeparator) {
        requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
      }
      int initialStart = this.scanner.initialPosition;
      int initialEnd = this.scanner.eofPosition;
      //			if (this.localDeclarationVisitor != null || fullParse){
      //				diet = false;
      //				this.getMethodBodies(parsedUnit);
      //			}
      this.scanner.resetTo(initialStart, initialEnd);
      notifySourceElementRequestor(parsedUnit);
      return parsedUnit;
    } catch (AbortCompilation e) {
      // ignore this exception
    } finally {
      //			diet = old;
    }
    return null;
  }

  public CompilationUnitDeclaration parseCompletionUnit(ICompilationUnit unit, boolean fullParse) {

    //		boolean old = diet;
    //		if (fullParse) {
    //			unknownRefs = new NameReference[10];
    //			unknownRefsCounter = 0;
    //		}

    try {
      //			diet = true;
      this.reportReferenceInfo = fullParse;
      CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
      CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, false);
//      if (scanner.recordLineSeparator) {
//        requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
//      }
//      int initialStart = this.scanner.initialPosition;
//      int initialEnd = this.scanner.eofPosition;
//      //			if (this.localDeclarationVisitor != null || fullParse){
//      //				diet = false;
//      //				this.getMethodBodies(parsedUnit);
//      //			}
//      this.scanner.resetTo(initialStart, initialEnd);
//      notifySourceElementRequestor(parsedUnit);
      return parsedUnit;
    } catch (AbortCompilation e) {
      // ignore this exception
    } finally {
      //			diet = old;
    }
    return null;
  }
  //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, // no need for field and methods
  //				false, // no need for member types
  //				false, // no need for field initialization
  //				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.taskTags = null;
  //		scanner.taskPriorities = null;
  //		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 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);
  //}
  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;
    }
  }
}