/*******************************************************************************
 * Copyright (c) 2004, 2019 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.tests.dom;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
import org.eclipse.jdt.core.dom.TypeParameter;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.WildcardType;
import org.eclipse.jdt.core.tests.model.ModifyingResourceTests;
import org.eclipse.jdt.core.tests.util.Util;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier;

@SuppressWarnings({"rawtypes", "unchecked"})
public class AbstractASTTests extends ModifyingResourceTests implements DefaultMarkedNodeLabelProviderOptions {

	/** @deprecated Using deprecated code */
	private static final int AST_INTERNAL_JLS2 = AST.JLS2;
	/**
	 * Internal synonym for deprecated constant AST.JSL3
	 * to alleviate deprecation warnings.
	 * @deprecated
	 */
	/*package*/ static final int AST_INTERNAL_JLS3 = AST.JLS3;
	/**
	 * Internal synonym for deprecated constant AST.JSL4
	 * to alleviate deprecation warnings.
	 * @deprecated
	 */
	/*package*/ static final int AST_INTERNAL_JLS4 = AST.JLS4;
	/**
	 * Internal synonym for deprecated constant AST.JSL8
	 * to alleviate deprecation warnings.
	 * @deprecated
	 */
	/*package*/ static final int AST_INTERNAL_JLS8 = AST.JLS8;
	public static final int astInternalJLS2() {
		return AST_INTERNAL_JLS2;
	}

	// TODO (frederic) use this field while converting instead of method argument
	protected int testLevel = AST_INTERNAL_JLS2;

	public AbstractASTTests(String name) {
		super(name);
	}

	public void setUpSuite() throws Exception {
		super.setUpSuite();
		
		SourceRangeVerifier.DEBUG = true;
		SourceRangeVerifier.DEBUG_THROW = true;
	}
	
	/*
	 * Removes the *start* and *end* markers from the given source
	 * and remembers the positions.
	 */
	public class MarkerInfo {
		String path;
		String source;

		String markerStartStart;
		String markerStartEnd;
		String markerEndStart;
		String markerEndEnd;

		int[] astStarts, astEnds;

		public MarkerInfo(String source) {
			this(null, source);
		}
		public MarkerInfo(String path, String source) {
			this(path, source, "/*", "*/", "start", "end");
		}
		public MarkerInfo(
				String source,
				String markerBeginning,
				String markerEnding,
				String markerStart,
				String markerEnd) {
			this(null, source, markerBeginning, markerEnding, markerStart, markerEnd);
		}

		public MarkerInfo(
				String path,
				String source,
				String markerBeginning,
				String markerEnding,
				String markerStart,
				String markerEnd) {
			this.path = path;
			this.source = source;

			this.markerStartStart = markerBeginning + markerStart;
			this.markerStartEnd = markerEnding;
			this.markerEndStart = markerBeginning + markerEnd;
			this.markerEndEnd = markerEnding;

			int markerIndex = 1;
			while (source.indexOf(this.markerStartStart + markerIndex + this.markerStartEnd) != -1) {
				markerIndex++;
			}
			int astNumber = source.indexOf(this.markerStartStart + this.markerStartEnd) != -1 ? markerIndex : markerIndex-1;
			this.astStarts = new int[astNumber];
			this.astEnds = new int[astNumber];

			for (int i = 1; i < markerIndex; i++)
				setStartAndEnd(i);
			if (astNumber == markerIndex)
				setStartAndEnd(-1);
		}

		public int indexOfASTStart(int astStart) {
			return this.indexOfASTStart(astStart, 0);
		}

		public int indexOfASTStart(int astStart, int fromIndex) {
			for (int i = fromIndex, length = this.astStarts.length; i < length; i++)
				if (this.astStarts[i] == astStart)
					return i;
			return -1;
		}

		private void removeMarkerFromSource(String marker, int sourceIndex, int astNumber) {
			int markerLength = marker.length();
			this.source = this.source.substring(0, sourceIndex).concat(this.source.substring(sourceIndex + markerLength));
			// shift previously recorded positions
			for (int i = 0; i < astNumber; i++) {
				if (this.astStarts[i] > sourceIndex)
					this.astStarts[i] -= markerLength;
				if (this.astEnds[i] > sourceIndex)
					this.astEnds[i] -= markerLength;
			}
		}

		private void setStartAndEnd(int markerIndex) {
			String markerNumber;
			if (markerIndex == -1) {
				markerNumber = "";
				markerIndex = this.astStarts.length; // *start* is always last
			} else
				markerNumber = Integer.toString(markerIndex);

			String markerStart = this.markerStartStart + markerNumber + this.markerStartEnd;
			String markerEnd = this.markerEndStart + markerNumber + this.markerEndEnd;
			int astStart = this.source.indexOf(markerStart); // start of AST inclusive
			this.astStarts[markerIndex-1] = astStart;
			removeMarkerFromSource(markerStart, astStart, markerIndex-1);
			int astEnd = this.source.indexOf(markerEnd); // end of AST exclusive
			this.astEnds[markerIndex-1] = astEnd;
			removeMarkerFromSource(markerEnd, astEnd, markerIndex-1);
		}

	}

	public class BindingRequestor extends ASTRequestor {
		HashMap bindings = new HashMap();
		public void acceptBinding(String bindingKey, IBinding binding) {
			this.bindings.put(bindingKey, binding);
		}
		public IBinding[] getBindings(String[] bindingKeys) {
			int length = this.bindings.size();
			IBinding[] result = new IBinding[length];
			for (int i = 0; i < length; i++) {
				result[i] = (IBinding) this.bindings.get(bindingKeys[i]);
			}
			return result;
		}
	}

	public static class ASTResult {
		public String result; // marked ast output
		public String source; // source without marker
		public ASTResult(String result, String source) {
			this.result = result;
			this.source = source;
		}
	}

	protected void assertASTNodeEquals(String expected, ASTNode node) {
		String actual = node.toString();
		if (!expected.equals(actual)) {
			System.out.println(displayString(actual, 3) + ",");
		}
		assertEquals("Unexpected ast node", expected, actual);
	}

	protected void assertASTNodesEqual(String expected, List nodes) {
		StringBuffer buffer = new StringBuffer();
		Iterator iterator = nodes.iterator();
		while (iterator.hasNext()) {
			ASTNode node = (ASTNode) iterator.next();
			buffer.append(node);
			if (node instanceof CompilationUnit) {
				IProblem[] problems = ((CompilationUnit) node).getProblems();
				if (problems != null) {
					for (int i = 0, length = problems.length; i < length; i++) {
						IProblem problem = problems[i];
						buffer.append('\n');
						buffer.append(problem);
					}
				}
			}
			buffer.append('\n');
		}
		String actual = buffer.toString();
		if (!expected.equals(actual)) {
			System.out.println(displayString(actual, 4) + ",");
		}
		assertEquals("Unexpected ast nodes", expected, actual);
	}

	protected void assertBindingKeyEquals(String expected, String actual) {
		assertBindingKeysEqual(expected, new String[] {actual});
	}

	protected void assertBindingKeysEqual(String expected, String[] actualKeys) {
		StringBuffer buffer = new StringBuffer();
		for (int i = 0, length = actualKeys.length; i < length; i++) {
			if (i > 0) buffer.append('\n');
			buffer.append(actualKeys[i]);
		}
		String actual = buffer.toString();
		if (!expected.equals(actual)) {
			System.out.print(displayString(actual, 4));
			System.out.println(',');
		}
		assertEquals(
			"Unexpected binding keys",
			expected,
			actual);
	}

	protected void assertBindingEquals(String expected, IBinding binding) {
		assertBindingsEqual(expected, new IBinding[] {binding});
	}

	protected void assertBindingsEqual(String expected, IBinding[] actualBindings) {
		assertBindingsEqual("Unexpected bindings", expected, actualBindings);
	}

	protected void assertBindingsEqual(String message, String expected, IBinding[] actualBindings) {
		StringBuffer buffer = new StringBuffer();
		for (int i = 0, length = actualBindings.length; i < length; i++) {
			if (i > 0) buffer.append('\n');
			if (actualBindings[i] == null)
				buffer.append("<null>");
			else
				buffer.append(actualBindings[i].getKey());
		}
		String actual = buffer.toString();
		if (!expected.equals(actual)) {
			System.out.print(displayString(actual, 3));
			System.out.println(',');
		}
		assertEquals(message, expected, actual);
	}

	protected void assertASTResult(
			String expected,
			ASTResult actual) throws JavaModelException {

		if (!expected.equals(actual.result)) {
			System.out.println();
			System.out.println(actual.source);
			System.out.println(Util.displayString(actual.result, 3));
		}

		assertEquals(expected, actual.result);
	}

	// TODO (frederic) replace all ASTParser creation with by calling this method
	protected ASTParser createASTParser() {
	    ASTParser parser = ASTParser.newParser(this.testLevel);
	    return parser;
    }
	/*
	 * Builds an AST from the info source (which is assumed to be the source attached to the given class file),
	 * and returns the AST node that was delimited by the astStart and astEnd of the marker info.
	 */
	protected ASTNode buildAST(MarkerInfo markerInfo, IClassFile classFile, boolean reportErrors) throws JavaModelException {
		ASTParser parser = ASTParser.newParser(AST_INTERNAL_JLS3);
		parser.setSource(classFile);
		parser.setResolveBindings(true);
		CompilationUnit unit = (CompilationUnit) parser.createAST(null);

		if (reportErrors) {
			StringBuffer buffer = new StringBuffer();
			IProblem[] problems = unit.getProblems();
			for (int i = 0, length = problems.length; i < length; i++)
				Util.appendProblem(buffer, problems[i], markerInfo.source.toCharArray(), i+1);
			if (buffer.length() > 0)
				assertEquals("Unexpected errors", "", buffer.toString());
		}

		return findNode(unit, markerInfo);
	}

	protected ASTNode buildAST(ICompilationUnit cu) throws JavaModelException {
		return buildAST(null/*use existing contents*/, cu, true/*report errors*/);
	}

	protected ASTNode buildAST(String newContents, ICompilationUnit cu) throws JavaModelException {
		return buildAST(newContents, cu, true/*report errors*/);
	}

	protected ASTNode buildAST(MarkerInfo markerInfo, IClassFile classFile) throws JavaModelException {
		return buildAST(markerInfo, classFile, true/*report errors*/);
	}

	/*
	 * Removes the marker comments "*start*" and "*end*" from the given contents,
	 * builds an AST from the resulting source, and returns the AST node that was delimited
	 * by "*start*" and "*end*".
	 */
	protected ASTNode buildAST(String newContents, ICompilationUnit cu, boolean reportErrors) throws JavaModelException {
		return buildAST(newContents, cu, reportErrors, false/*no statement recovery*/, false);
	}

	protected ASTNode buildAST(int JLSLevel, String newContents, ICompilationUnit cu, boolean reportErrors, boolean enableStatementRecovery, boolean bindingRecovery) throws JavaModelException {
		ASTNode[] nodes = buildASTs(JLSLevel, newContents, cu, reportErrors, enableStatementRecovery, bindingRecovery);
		if (nodes.length == 0) return null;
		return nodes[0];
	}
	protected ASTNode buildAST(String newContents, ICompilationUnit cu, boolean reportErrors, boolean enableStatementRecovery, boolean bindingRecovery) throws JavaModelException {
		ASTNode[] nodes = buildASTs(newContents, cu, reportErrors, enableStatementRecovery, bindingRecovery);
		if (nodes.length == 0) return null;
		return nodes[0];
	}

	protected ASTNode buildAST(String newContents, ICompilationUnit cu, boolean reportErrors, boolean enableStatementRecovery) throws JavaModelException {
		ASTNode[] nodes = buildASTs(newContents, cu, reportErrors, enableStatementRecovery, false);
		if (nodes.length == 0) return null;
		return nodes[0];
	}

	protected ASTNode buildAST(String newContents, ICompilationUnit cu, int flags) throws JavaModelException {
		ASTNode[] nodes = buildASTs(newContents, cu, flags);
		if (nodes.length == 0) return null;
		return nodes[0];
	}

	private ASTNode[] buildASTs(String newContents, ICompilationUnit cu, int flags) throws JavaModelException {
		MarkerInfo markerInfo;
		if (newContents == null) {
			markerInfo = new MarkerInfo(cu.getSource());
		} else {
			markerInfo = new MarkerInfo(newContents);
		}
		newContents = markerInfo.source;

		CompilationUnit unit;
		if (cu.isWorkingCopy()) {
			cu.getBuffer().setContents(newContents);
			unit = cu.reconcile(AST_INTERNAL_JLS3, flags, null, null);
		} else {
			IBuffer buffer = cu.getBuffer();
			buffer.setContents(newContents);
			buffer.save(null, false);

			ASTParser parser = ASTParser.newParser(AST_INTERNAL_JLS3);
			parser.setSource(cu);
			parser.setResolveBindings(true);
			parser.setStatementsRecovery((flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
			unit = (CompilationUnit) parser.createAST(null);
		}

		if ((flags & ICompilationUnit.FORCE_PROBLEM_DETECTION) != 0) {
			StringBuffer buffer = new StringBuffer();
			IProblem[] problems = unit.getProblems();
			for (int i = 0, length = problems.length; i < length; i++)
				Util.appendProblem(buffer, problems[i], newContents.toCharArray(), i+1);
			if (buffer.length() > 0)
				assertEquals("Unexpected errors", "", buffer.toString());
		}

		ASTNode[] nodes = findNodes(unit, markerInfo);
		if (nodes.length == 0)
			return new ASTNode[] {unit};
		return nodes;
	}

	protected ASTNode[] buildASTs(String contents, ICompilationUnit cu) throws JavaModelException {
		return buildASTs(contents, cu, true);
	}

	/*
	 * Removes the marker comments "*start?*" and "*end?*" from the given new contents
	 * (where ? is either empty or a number), or use the current contents if the given new contents is null.
	 * Builds an AST from the resulting source.
	 * For each of the pairs, returns the AST node that was delimited by "*start?*" and "*end?*".
	 */
	protected ASTNode[] buildASTs(String newContents, ICompilationUnit cu, boolean reportErrors) throws JavaModelException {
		return buildASTs(newContents, cu, reportErrors, false, false);
	}
	protected ASTNode[] buildASTs(int JLSLevel, String newContents, ICompilationUnit cu, boolean reportErrors, boolean enableStatementRecovery, boolean bindingRecovery) throws JavaModelException {
		MarkerInfo markerInfo;
		if (newContents == null) {
			markerInfo = new MarkerInfo(cu.getSource());
		} else {
			markerInfo = new MarkerInfo(newContents);
		}
		newContents = markerInfo.source;

		CompilationUnit unit;
		if (cu.isWorkingCopy()) {
			cu.getBuffer().setContents(newContents);
			int flags = 0;
			if (reportErrors) flags |= ICompilationUnit.FORCE_PROBLEM_DETECTION;
			if (enableStatementRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
			if (bindingRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
			unit = cu.reconcile(JLSLevel, flags, null, null);
		} else {
			IBuffer buffer = cu.getBuffer();
			buffer.setContents(newContents);
			buffer.save(null, false);

			ASTParser parser = ASTParser.newParser(JLSLevel);
			parser.setSource(cu);
			parser.setResolveBindings(true);
			parser.setStatementsRecovery(enableStatementRecovery);
			parser.setBindingsRecovery(bindingRecovery);
			unit = (CompilationUnit) parser.createAST(null);
		}

		if (reportErrors) {
			StringBuffer buffer = new StringBuffer();
			IProblem[] problems = unit.getProblems();
			for (int i = 0, length = problems.length; i < length; i++)
				Util.appendProblem(buffer, problems[i], newContents.toCharArray(), i+1);
			if (buffer.length() > 0)
				assertEquals("Unexpected errors", "", buffer.toString());
		}

		ASTNode[] nodes = findNodes(unit, markerInfo);
		if (nodes.length == 0)
			return new ASTNode[] {unit};
		return nodes;
	}
	@SuppressWarnings("deprecation")
	protected ASTNode[] buildASTs(String newContents, ICompilationUnit cu, boolean reportErrors, boolean enableStatementRecovery, boolean bindingRecovery) throws JavaModelException {
		String option = cu.getJavaProject().getOption(JavaCore.COMPILER_COMPLIANCE, true);
		long jdkLevel = CompilerOptions.versionToJdkLevel(option);
		int JLSLevel = AST_INTERNAL_JLS3;
		if (jdkLevel >= ClassFileConstants.getComplianceLevelForJavaVersion(ClassFileConstants.MAJOR_VERSION_13)) {
			JLSLevel = AST_INTERNAL_JLS13;
		} else if (jdkLevel >= ClassFileConstants.getComplianceLevelForJavaVersion(ClassFileConstants.MAJOR_VERSION_12)) {
			JLSLevel = AST_INTERNAL_JLS12;
		} else if (jdkLevel >= ClassFileConstants.getComplianceLevelForJavaVersion(ClassFileConstants.MAJOR_VERSION_11)) {
			JLSLevel = AST_INTERNAL_JLS11;			
		} else if (jdkLevel >= ClassFileConstants.JDK10) {
			JLSLevel = AST_INTERNAL_JLS10;			
		} else if (jdkLevel >= ClassFileConstants.JDK9) {
			JLSLevel = AST_INTERNAL_JLS9;			
		} else if (jdkLevel >= ClassFileConstants.JDK1_8) {
			JLSLevel = AST_INTERNAL_JLS8;
		} else if (jdkLevel >= ClassFileConstants.JDK1_7) {
			JLSLevel = AST_INTERNAL_JLS4;
		}
		return buildASTs(
				JLSLevel,
				newContents,
				cu,
				reportErrors,
				enableStatementRecovery,
				bindingRecovery);
	}

	protected ASTResult buildMarkedAST(
			String path,
			String content) throws JavaModelException {
		return
			this.buildMarkedAST(
					path,
					content,
					true, // enable statement recovery
					true, // report ast
					true, // report problems
					new MarkedASTFlattener.DefaultMarkedNodeLabelProvider(ALL_OPTIONS));
	}

	protected ASTResult buildMarkedAST(
			String path,
			String content,
			boolean enableStatementRecovery,
			boolean reportAST,
			boolean reportProblems,
			int options) throws JavaModelException {
		return
			this.buildMarkedAST(
					path,
					content,
					enableStatementRecovery,
					reportAST,
					reportProblems,
					new MarkedASTFlattener.DefaultMarkedNodeLabelProvider(options));
	}

	/*
	 * Removes the marker comments "[*?*]" from the given new contents
	 * (where ? is either empty or a number), or use the current contents if the given new contents is null.
	 * Builds an AST from the resulting source and information about marked nodes.
	 */
	protected ASTResult buildMarkedAST(
			String path,
			String content,
			boolean enableStatementRecovery,
			boolean reportAST,
			boolean reportProblems,
			MarkedASTFlattener.DefaultMarkedNodeLabelProvider labelProvider) throws JavaModelException {

		MarkerInfo markerInfo;
		markerInfo = new MarkerInfo(content, "[*", "*]", "", "");
		content = markerInfo.source;

		ICompilationUnit compilationUnit = getWorkingCopy(path, content, true);

		ASTParser parser = createASTParser();
		parser.setSource(compilationUnit);
		parser.setResolveBindings(true);
		parser.setWorkingCopyOwner(this.wcOwner);
		parser.setStatementsRecovery(enableStatementRecovery);
		CompilationUnit unit = (CompilationUnit)parser.createAST(null);

		MarkedASTFlattener flattener =
			new MarkedASTFlattener(
					reportAST,
					reportProblems,
					labelProvider);
		flattener.process(unit, markerInfo);

		ASTResult result = new ASTResult(flattener.getResult(), markerInfo.source);

		compilationUnit.discardWorkingCopy();

		return result;
	}

	protected MarkerInfo[] createMarkerInfos(String[] pathAndSources) {
		MarkerInfo[] markerInfos = new MarkerInfo[pathAndSources.length / 2];
		int index = 0;
		for (int i = 0, length = pathAndSources.length; i < length; i++) {
			String path = pathAndSources[i];
			String source = pathAndSources[++i];
			markerInfos[index++] = new MarkerInfo(path, source);
		}
		return markerInfos;
	}

	protected IVariableBinding[] createVariableBindings(String[] pathAndSources, String[] bindingKeys) throws JavaModelException {
		WorkingCopyOwner owner = new WorkingCopyOwner() {};
		this.workingCopies = createWorkingCopies(pathAndSources, owner);
		IBinding[] bindings = resolveBindings(bindingKeys, getJavaProject("P"), owner);
		int length = bindings.length;
		IVariableBinding[] result = new IVariableBinding[length];
		System.arraycopy(bindings, 0, result, 0, length);
		return result;
	}

	protected IMethodBinding[] createMethodBindings(String[] pathAndSources, String[] bindingKeys) throws JavaModelException {
		return createMethodBindings(pathAndSources, bindingKeys, getJavaProject("P"));
	}

	protected IMethodBinding[] createMethodBindings(String[] pathAndSources, String[] bindingKeys, IJavaProject project) throws JavaModelException {
		WorkingCopyOwner owner = new WorkingCopyOwner() {};
		this.workingCopies = createWorkingCopies(pathAndSources, owner);
		IBinding[] bindings = resolveBindings(bindingKeys, project, owner);
		int length = bindings.length;
		IMethodBinding[] result = new IMethodBinding[length];
		System.arraycopy(bindings, 0, result, 0, length);
		return result;
	}

	protected ITypeBinding[] createTypeBindings(String[] pathAndSources, String[] bindingKeys) throws JavaModelException {
		return createTypeBindings(pathAndSources, bindingKeys, getJavaProject("P"));
	}

	protected ITypeBinding[] createTypeBindings(String[] pathAndSources, String[] bindingKeys, IJavaProject project) throws JavaModelException {
		WorkingCopyOwner owner = new WorkingCopyOwner() {};
		this.workingCopies = createWorkingCopies(pathAndSources, owner);
		IBinding[] bindings = resolveBindings(bindingKeys, project, owner);
		int length = bindings.length;
		ITypeBinding[] result = new ITypeBinding[length];
		System.arraycopy(bindings, 0, result, 0, length);
		return result;
	}

	protected ICompilationUnit[] createWorkingCopies(String[] pathAndSources, WorkingCopyOwner owner) throws JavaModelException {
		MarkerInfo[] markerInfos = createMarkerInfos(pathAndSources);
		return createWorkingCopies(markerInfos, owner);
	}

	protected ICompilationUnit[] createWorkingCopies(MarkerInfo[] markerInfos, WorkingCopyOwner owner) throws JavaModelException {
		int length = markerInfos.length;
		ICompilationUnit[] copies = new ICompilationUnit[length];
		for (int i = 0; i < length; i++) {
			MarkerInfo markerInfo = markerInfos[i];
			ICompilationUnit workingCopy = getCompilationUnit(markerInfo.path).getWorkingCopy(owner, null);
			workingCopy.getBuffer().setContents(markerInfo.source);
			workingCopy.makeConsistent(null);
			copies[i] = workingCopy;
		}
		return copies;
	}

	protected ASTNode findNode(CompilationUnit unit, final MarkerInfo markerInfo) {
		ASTNode[] nodes = findNodes(unit, markerInfo);
		if (nodes.length == 0)
			return unit;
		return nodes[0];
	}

	protected ASTNode[] findNodes(CompilationUnit unit, final MarkerInfo markerInfo) {
		class Visitor extends ASTVisitor {
			ArrayList found = new ArrayList();
			public void preVisit(ASTNode node) {
				if (node instanceof CompilationUnit) return;
				int index = markerInfo.indexOfASTStart(node.getStartPosition());
				if (index != -1 && node.getStartPosition() + node.getLength() == markerInfo.astEnds[index]) {
					this.found.add(node);
					markerInfo.astStarts[index] = -1; // so that 2 nodes with the same start and end will not be found
				}
			}
		}
		Visitor visitor = new Visitor();
		unit.accept(visitor);
		int size = visitor.found.size();
		ASTNode[] result = new ASTNode[size];
		visitor.found.toArray(result);
		return result;
	}

	/**
	 * Create a new working copy owner using given problem requestor
	 * to report problem.
	 *
	 * @param problemRequestor The requestor used to report problems
	 * @return The created working copy owner
	 */
	protected WorkingCopyOwner newWorkingCopyOwner(final IProblemRequestor problemRequestor) {
		return new WorkingCopyOwner() {
			public IProblemRequestor getProblemRequestor(ICompilationUnit unit) {
				return problemRequestor;
			}
		};
	}

	protected void resolveASTs(ICompilationUnit[] cus, String[] bindingKeys, ASTRequestor requestor, IJavaProject project, WorkingCopyOwner owner) {
		ASTParser parser = ASTParser.newParser(AST_INTERNAL_JLS3);
		parser.setResolveBindings(true);
		parser.setProject(project);
		parser.setWorkingCopyOwner(owner);
		parser.createASTs(cus, bindingKeys,  requestor, null);
	}

	protected IBinding resolveBinding(ASTNode node) {
		switch (node.getNodeType()) {
			case ASTNode.PACKAGE_DECLARATION:
				return ((PackageDeclaration) node).resolveBinding();
			case ASTNode.TYPE_DECLARATION:
				return ((TypeDeclaration) node).resolveBinding();
			case ASTNode.ANONYMOUS_CLASS_DECLARATION:
				return ((AnonymousClassDeclaration) node).resolveBinding();
			case ASTNode.TYPE_DECLARATION_STATEMENT:
				return ((TypeDeclarationStatement) node).resolveBinding();
			case ASTNode.METHOD_DECLARATION:
				return ((MethodDeclaration) node).resolveBinding();
			case ASTNode.METHOD_INVOCATION:
				return ((MethodInvocation) node).resolveMethodBinding();
			case ASTNode.TYPE_PARAMETER:
				return ((TypeParameter) node).resolveBinding();
			case ASTNode.PARAMETERIZED_TYPE:
				return ((ParameterizedType) node).resolveBinding();
			case ASTNode.WILDCARD_TYPE:
				return ((WildcardType) node).resolveBinding();
			case ASTNode.SIMPLE_NAME:
				return ((SimpleName) node).resolveBinding();
			case ASTNode.ARRAY_TYPE:
				return ((ArrayType) node).resolveBinding();
			case ASTNode.ASSIGNMENT:
				return ((Assignment) node).getRightHandSide().resolveTypeBinding();
			case ASTNode.SIMPLE_TYPE:
				return ((SimpleType) node).resolveBinding();
			case ASTNode.QUALIFIED_NAME:
				return ((QualifiedName) node).resolveBinding();
			case ASTNode.MARKER_ANNOTATION:
				return ((MarkerAnnotation) node).resolveAnnotationBinding();
			case ASTNode.NORMAL_ANNOTATION:
				return ((NormalAnnotation) node).resolveAnnotationBinding();
			case ASTNode.SINGLE_MEMBER_ANNOTATION:
				return ((SingleMemberAnnotation) node).resolveAnnotationBinding();
			case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
				return ((VariableDeclarationFragment) node).resolveBinding();
			default:
				throw new Error("Not yet implemented for this type of node: " + node);
		}
	}

	protected IBinding[] resolveBindings(String[] bindingKeys, IJavaProject project, WorkingCopyOwner owner) {
		BindingRequestor requestor = new BindingRequestor();
		resolveASTs(new ICompilationUnit[0], bindingKeys, requestor, project, owner);
		return requestor.getBindings(bindingKeys);
	}

	/*
	 * Resolve the bindings of the nodes marked with *start?* and *end?*.
	 */
	protected IBinding[] resolveBindings(String contents, ICompilationUnit cu) throws JavaModelException {
		return resolveBindings(contents, cu, true/*report errors*/);
	}

	/*
	 * Resolve the bindings of the nodes marked with *start?* and *end?*.
	 */
	protected IBinding[] resolveBindings(String contents, ICompilationUnit cu, boolean reportErrors) throws JavaModelException {
		ASTNode[] nodes = buildASTs(contents, cu, reportErrors);
		if (nodes == null) return null;
		int length = nodes.length;
		IBinding[] result = new IBinding[length];
		for (int i = 0; i < length; i++) {
			result[i] = resolveBinding(nodes[i]);
		}
		return result;
	}

	protected ASTNode buildAST(IClassFile classFile) throws JavaModelException {
		String source = classFile.getSource();
		MarkerInfo markerInfo = new MarkerInfo(source);
		markerInfo.astStarts = new int[] {source.indexOf("/*start*/") + "/*start*/".length()};
		markerInfo.astEnds = new int[] {source.indexOf("/*end*/")};
		ASTNode node = buildAST(markerInfo, classFile);
		return node;
	}


//	protected void tearDown() throws Exception {
//		discardWorkingCopies(this.workingCopies);
//		this.workingCopies = null;
//	}

}
