/*******************************************************************************
 * Copyright (c) 2004, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.tests.dom;

import java.io.IOException;
import java.util.ArrayList;

import junit.framework.Test;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IProblemRequestor;
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.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.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.tests.util.Util;

@SuppressWarnings({"rawtypes", "unchecked"})
public class BatchASTCreationTests extends AbstractASTTests {

	/**
	 * Internal synonym for deprecated constant AST.JSL3
	 * to alleviate deprecation warnings.
	 * @deprecated
	 */
	/*package*/ static final int JLS3_INTERNAL = AST.JLS3;
	
	public class TestASTRequestor extends ASTRequestor {
		public ArrayList asts = new ArrayList();
		public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
			this.asts.add(ast);
		}
		public void acceptBinding(String bindingKey, IBinding binding) {
		}
	}

	class BindingResolver extends TestASTRequestor {
		private ArrayList bindingKeys = new ArrayList();
		int index = -1;
		private ArrayList foundKeys = new ArrayList();
		MarkerInfo[] markerInfos;
		public BindingResolver(MarkerInfo[] markerInfos) {
			this.markerInfos = markerInfos;
		}
		public void acceptAST(ICompilationUnit source, CompilationUnit cu) {
			super.acceptAST(source, cu);
			ASTNode[] nodes = findNodes(cu, this.markerInfos[++this.index]);
			for (int i = 0, length = nodes.length; i < length; i++) {
				IBinding binding = resolveBinding(nodes[i]);
				String bindingKey = binding == null ? "null" : binding.getKey();

				// case of a capture binding
				if (bindingKey.indexOf('!') != -1 && binding.getKind() == IBinding.METHOD) {
					bindingKey = ((IMethodBinding) binding).getReturnType().getKey();
				}

				this.bindingKeys.add(bindingKey);
			}
		}
		public void acceptBinding(String key, IBinding binding) {
			super.acceptBinding(key, binding);
			this.foundKeys.add(binding == null ? "null" : binding.getKey());
		}

		public String[] getBindingKeys() {
			int length = this.bindingKeys.size();
			String[] result = new String[length];
			this.bindingKeys.toArray(result);
			return result;
		}

		public String[] getFoundKeys() {
			int length = this.foundKeys.size();
			String[] result = new String[length];
			this.foundKeys.toArray(result);
			return result;
		}
	}

	public WorkingCopyOwner owner = new WorkingCopyOwner() {};

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

	public static Test suite() {
		return buildModelTestSuite(BatchASTCreationTests.class);
	}

	// Use this static initializer to specify subset for tests
	// All specified tests which do not belong to the class are skipped...
	static {
//		TESTS_PREFIX =  "testBug86380";
//		TESTS_NAMES = new String[] { "test072a" };
//		TESTS_NUMBERS = new int[] { 72 };
//		TESTS_RANGE = new int[] { 83304, -1 };
	}

	public void setUpSuite() throws Exception {
		super.setUpSuite();
		createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "", "1.5");
	}

	public void tearDownSuite() throws Exception {
		deleteProject("P");
		super.tearDownSuite();
	}

	/*
	 * Resolves the given cus and binding key as a batch.
	 * While resolving, for the ASTNode that is marked, ensures that its binding key is the expected one.
	 * Ensures that the returned binding corresponds to the expected key.
	 */
	private void assertRequestedBindingFound(String[] pathAndSources, final String expectedKey) throws JavaModelException {
		assertRequestedBindingsFound(pathAndSources, new String[] {expectedKey});
	}

	/*
	 * Resolves the given cus and binding key as a batch.
	 * While resolving, for the ASTNode that is marked, ensures that its binding key is the expected one.
	 * Ensures that the returned binding corresponds to the expected key.
	 */
	private void assertRequestedBindingsFound(String[] pathAndSources, final String[] expectedKeys) throws JavaModelException {
		BindingResolver resolver = requestBindings(pathAndSources, expectedKeys);

		assertStringsEqual("Unexpected binding for marked node", expectedKeys, resolver.getBindingKeys());

		assertStringsEqual("Unexpected binding found by acceptBinding", expectedKeys, resolver.getFoundKeys());
	}

	/*
	 * Creates working copies from the given path and sources.
	 * Resolves a dummy cu as a batch and on the first accept, create a binding with the expected key using ASTRequestor#createBindings.
	 * Ensures that the returned binding corresponds to the expected key.
	 */
	private void assertBindingCreated(String[] pathAndSources, final String expectedKey) throws JavaModelException {
		assertBindingsCreated(pathAndSources, new String[] {expectedKey});
	}
	/*
	 * Creates working copies from the given path and sources.
	 * Resolves a dummy cu as a batch and on the first accept, create a binding with the expected key using ASTRequestor#createBindings.
	 * Ensures that the returned binding corresponds to the expected key.
	 */
	private void assertBindingsCreated(String[] pathAndSources, final String[] expectedKeys) throws JavaModelException {
		ICompilationUnit[] copies = null;
		try {
			copies = createWorkingCopies(pathAndSources);
			class Requestor extends TestASTRequestor {
				ArrayList createdBindingKeys = new ArrayList();
				public void acceptAST(ICompilationUnit source, CompilationUnit cu) {
					super.acceptAST(source, cu);
					IBinding[] bindings = createBindings(expectedKeys);
					if (bindings != null && bindings.length > 0 && bindings[0] != null)
						this.createdBindingKeys.add(bindings[0].getKey());
				}
				public String getCreatedKeys() {
					StringBuffer buffer = new StringBuffer();
					for (int i = 0, length = this.createdBindingKeys.size(); i < length; i++) {
						buffer.append(this.createdBindingKeys.get(i));
						if (i < length - 1)
							buffer.append('\n');
					}
					return buffer.toString();
				}
			}
			Requestor requestor = new Requestor();
			ICompilationUnit[] dummyWorkingCopies = null;
			try {
				dummyWorkingCopies = createWorkingCopies(new String[] {
					"/P/Test.java",
					"public class Test {\n" +
					"}"
				});
				resolveASTs(dummyWorkingCopies, new String[] {}, requestor, getJavaProject("P"), this.owner);
			} finally {
				discardWorkingCopies(dummyWorkingCopies);
			}

			String expectedKey = toString(expectedKeys);
			String actualKey = requestor.getCreatedKeys();
			if (!expectedKey.equals(actualKey)) {
				BindingResolver resolver = requestBindings(pathAndSources, null);
				String[] markedKeys = resolver.getBindingKeys();
				if (markedKeys.length > 0) {
					assertStringsEqual("Inconsistent expected key ", expectedKeys, markedKeys);
				}
			}
			assertEquals("Unexpected created binding", expectedKey, actualKey);
		} finally {
			discardWorkingCopies(copies);
		}
	}

	private void createASTs(ICompilationUnit[] cus, TestASTRequestor requestor) {
		ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.createASTs(cus, new String[] {}, requestor, null);
	}

	protected ICompilationUnit[] createWorkingCopies(String[] pathAndSources) throws JavaModelException {
		return createWorkingCopies(pathAndSources, this.owner);
	}

	protected ICompilationUnit[] createWorkingCopies(String[] pathAndSources, boolean resolve) throws JavaModelException {
		IProblemRequestor problemRequestor = resolve
			? new IProblemRequestor() {
				public void acceptProblem(IProblem problem) {}
				public void beginReporting() {}
				public void endReporting() {}
				public boolean isActive() {
					return true;
				}
			}
			: null;
		MarkerInfo[] markerInfos = createMarkerInfos(pathAndSources);
		this.owner = newWorkingCopyOwner(problemRequestor);
		return createWorkingCopies(markerInfos, this.owner);
	}

	private void resolveASTs(ICompilationUnit[] cus, TestASTRequestor requestor) {
		resolveASTs(cus, new String[0], requestor, getJavaProject("P"), this.owner);
	}

	private BindingResolver requestBindings(String[] pathAndSources, final String[] expectedKeys) throws JavaModelException {
		ICompilationUnit[] copies = null;
		try {
			MarkerInfo[] markerInfos = createMarkerInfos(pathAndSources);
			copies = createWorkingCopies(markerInfos, this.owner);
			BindingResolver resolver = new BindingResolver(markerInfos);
			resolveASTs(copies, expectedKeys == null ? new String[0] : expectedKeys, resolver, copies.length > 0 ? copies[0].getJavaProject() : getJavaProject("P"), this.owner);
			return resolver;
		} finally {
			discardWorkingCopies(copies);
		}
	}


	/*
	 * Tests the batch creation of 2 ASTs without resolving.
	 */
	public void test001() throws CoreException {
		this.workingCopies = createWorkingCopies(new String[] {
			"/P/p1/X.java",
			"package p1;\n" +
			"public class X extends Y {\n" +
			"}",
			"/P/p1/Y.java",
			"package p1;\n" +
			"public class Y {\n" +
			"}",
		});
		TestASTRequestor requestor = new TestASTRequestor();
		createASTs(this.workingCopies, requestor);
		assertASTNodesEqual(
			"package p1;\n" +
			"public class X extends Y {\n" +
			"}\n" +
			"\n" +
			"package p1;\n" +
			"public class Y {\n" +
			"}\n" +
			"\n",
			requestor.asts
		);
	}

	/*
	 * Tests the batch creation of 2 ASTs with resolving.
	 */
	public void test002() throws CoreException {
		MarkerInfo[] markerInfos = createMarkerInfos(new String[] {
			"/P/p1/X.java",
			"package p1;\n" +
			"public class X extends /*start*/Y/*end*/ {\n" +
			"}",
			"/P/p1/Y.java",
			"package p1;\n" +
			"/*start*/public class Y {\n" +
			"}/*end*/",
		});
		this.workingCopies = createWorkingCopies(markerInfos, this.owner);
		TestASTRequestor requestor = new TestASTRequestor();
		resolveASTs(this.workingCopies, requestor);

		assertASTNodesEqual(
			"package p1;\n" +
			"public class X extends Y {\n" +
			"}\n" +
			"\n" +
			"package p1;\n" +
			"public class Y {\n" +
			"}\n" +
			"\n",
			requestor.asts
		);

		// compare the bindings coming from the 2 ASTs
		Type superX = (Type) findNode((CompilationUnit) requestor.asts.get(0), markerInfos[0]);
		TypeDeclaration typeY = (TypeDeclaration) findNode((CompilationUnit) requestor.asts.get(1), markerInfos[1]);
		IBinding superXBinding = superX.resolveBinding();
		IBinding typeYBinding = typeY.resolveBinding();
		assertTrue("Super of X and Y should be the same", superXBinding == typeYBinding);
	}

	/*
	 * Ensures that ASTs that are required by original source but were not asked for are not handled.
	 */
	public void test003() throws CoreException {
		ICompilationUnit[] otherWorkingCopies = null;
		try {
			this.workingCopies = createWorkingCopies(new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X extends Y {\n" +
				"}",
			});
			otherWorkingCopies = createWorkingCopies(new String[] {
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y {\n" +
				"}",
			});
			TestASTRequestor requestor = new TestASTRequestor();
			resolveASTs(this.workingCopies, requestor);

			assertASTNodesEqual(
				"package p1;\n" +
				"public class X extends Y {\n" +
				"}\n" +
				"\n",
				requestor.asts
			);
		} finally {
			// Note: this.workingCopies are discarded in tearDown
			discardWorkingCopies(otherWorkingCopies);
		}
	}

	/*
	 * Ensures that a package binding can be retrieved using its key.
	 */
	public void test004() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"/*start*/package p1;/*end*/\n" +
				"public class X {\n" +
				"}",
			},
			"p1");
	}

	/*
	 * Ensures that a type binding can be retrieved using its key.
	 */
	public void test005() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"/*start*/public class X extends Y {\n" +
				"}/*end*/",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y {\n" +
				"}",
			},
			"Lp1/X;");
	}

	/*
	 * Ensures that a type binding can be retrieved using its key.
	 */
	public void test006() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X extends Y {\n" +
				"}",
				"/P/p1/Y.java",
				"package p1;\n" +
				"/*start*/public class Y {\n" +
				"}/*end*/",
			},
			"Lp1/Y;");
	}

	/*
	 * Ensures that a member type binding can be retrieved using its key.
	 */
	public void test007() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  /*start*/class Member {\n" +
				"  }/*end*/" +
				"}",
			},
			"Lp1/X$Member;");
	}

	/*
	 * Ensures that a member type binding can be retrieved using its key.
	 */
	public void test008() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  class Member1 {\n" +
				"    /*start*/class Member2 {\n" +
				"    }/*end*/" +
				"  }\n" +
				"}",
			},
			"Lp1/X$Member1$Member2;");
	}
	/*
	 * Ensures that an anonymous type binding can be retrieved using its key.
	 */
	public void test009() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    new X() /*start*/{\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			},
			"Lp1/X$52;");
	}
	/*
	 * Ensures that a local type binding can be retrieved using its key.
	 */
	public void test010() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    /*start*/class Y {\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			},
			"Lp1/X$54$Y;");
	}

	/*
	 * Ensures that a package binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test011() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"}",
			},
			"p1");
	}

	/*
	 * Ensures that a type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test012() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X extends Y {\n" +
				"}",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y {\n" +
				"}",
			},
			"Lp1/X;");
	}

	/*
	 * Ensures that a type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test013() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X extends Y {\n" +
				"}",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y {\n" +
				"}",
			},
			"Lp1/Y;");
	}

	/*
	 * Ensures that a member type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test014() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  class Member {\n" +
				"  }" +
				"}",
			},
			"Lp1/X$Member;");
	}

	/*
	 * Ensures that a member type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test015() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  class Member1 {\n" +
				"    class Member2 {\n" +
				"    }" +
				"  }\n" +
				"}",
			},
			"Lp1/X$Member1$Member2;");
	}

	/*
	 * Ensures that an anonymous type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test016() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    new X() /*start*/{\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			},
			"Lp1/X$52;");
	}

	/*
	 * Ensures that a local type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test017() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    /*start*/class Y {\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			},
			"Lp1/X$54$Y;");
	}

	/*
	 * Ensures that a method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test018() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo()V");
	}

	/*
	 * Ensures that a method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test019() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo(Object o) {\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo(Ljava/lang/Object;)V");
	}

	/*
	 * Ensures that a method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test020() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  X(Object o) {\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.(Ljava/lang/Object;)V");
	}

	/*
	 * Ensures that a field binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test021() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  int field;\n" +
				"}",
			},
			"Lp1/X;.field)I");
	}

	/*
	 * Ensures that a base type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test022() throws CoreException {
		assertBindingCreated(new String[0],"I");
	}

	/*
	 * Ensures that an array binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test023() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"}",
			},
			"[Lp1/X;");
	}

	/*
	 * Ensures that an array binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test024() throws CoreException {
		assertBindingCreated(new String[0],"[[I");
	}

	/*
	 * Ensures that a method binding in an anonymous type with several kind of parameters can be created using its key in ASTRequestor#createBindings
	 */
	public void test025() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  class Y {\n" +
				"  }\n" +
				"  void foo() {\n" +
				"    new X() {\n" +
				"      /*start*/void bar(int i, X x, String[][] s, Y[] args, boolean b, Object o) {\n" +
				"      }/*end*/\n" +
				"    };\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X$68;.bar(ILp1/X;[[Ljava/lang/String;[Lp1/X$Y;ZLjava/lang/Object;)V"
		);
	}

	/*
	 * Ensures that a generic type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test026() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"}",
			},
			"Lp1/X<TT;>;");
	}

	/*
	 * Ensures that a generic type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test027() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T extends Y & I, U extends Y> {\n" +
				"}",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y {\n" +
				"}",
				"/P/p1/I.java",
				"package p1;\n" +
				"public interface I {\n" +
				"}",
			},
			"Lp1/X<TT;TU;>;");
	}

	/*
	 * Ensures that a parameterized type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test028() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  X<String> field;\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/String;>;");
	}

	/*
	 * Ensures that a member parameterized type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test029() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T,U> {\n" +
				"  class Y<V> {\n" +
				"    X<Error,Exception>.Y<String> field;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/Error;Ljava/lang/Exception;>.Y<Ljava/lang/String;>;");
	}

	/*
	 * Ensures that a raw type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test030() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T,U> {\n" +
				"   X field;\n" +
				"}",
			},
			"Lp1/X<>;");
	}

	/*
	 * Ensures that a member raw type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test031() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T,U> {\n" +
				"  class Y<V> {\n" +
				"    X<Error,Exception>.Y field;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/Error;Ljava/lang/Exception;>.Y<>;");
	}

	/*
	 * Ensures that a parameterized method binding can be created using its key in ASTRequestor#createBindings
	 */
	public void test032() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  <T> void foo() {\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo<T:Ljava/lang/Object;>()V");
	}

	/*
	 * Ensures that a local variable binding can be created using its key in ASTRequestor#createBindings
	 */
	public void test033() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    int i;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo()V#i");
	}

	/*
	 * Ensures that a local variable binding can be created using its key in ASTRequestor#createBindings
	 */
	public void test034() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    int i = 1;\n" +
				"    if (i == 0) {\n" +
				"      int a;\n" +
				"    } else {\n" +
				"      int b;\n" +
				"    }\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo()V#1#b");
	}

	/*
	 * Ensures that a parameterized method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test035() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  void foo(T t) {\n" +
				"  }\n" +
				"  void bar() {\n" +
				"    new X<String>().foo(\"\");\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/String;>;.foo(Ljava/lang/String;)V");
	}

	/*
	 * Ensures that a parameterized generic method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test036() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  <U> void foo(T t, U u) {\n" +
				"  }\n" +
				"  void bar() {\n" +
				"    /*start*/new X<String>().foo(\"\", this)/*end*/;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/String;>;.foo<U:Ljava/lang/Object;>(Ljava/lang/String;TU;)V%<Lp1/X;>"
		);
	}

	/*
	 * Ensures that a raw generic method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test037() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  <U> void foo(T t, U u) {\n" +
				"  }\n" +
				"  void bar() {\n" +
				"    /*start*/new X().foo(\"\", this)/*end*/;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo<U:Ljava/lang/Object;>(TT;TU;)V%<>");
	}

	/*
	 * Ensures that a parameterized method binding (where the parameter is an unbound wildcard) can be created using its key in ASTRequestor#createBindings.
	 */
	public void test038() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  void foo() {\n" +
				"  }\n" +
				"  void bar(X<?> x) {\n" +
				"    x.foo();\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Lp1/X;{0}*>;.foo()V");
	}

	/*
	 * Ensures that a parameterized method binding (where the parameter is an extends wildcard) can be created using its key in ASTRequestor#createBindings.
	 */
	public void test039() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  void foo() {\n" +
				"  }\n" +
				"  void bar(X<? extends Object> x) {\n" +
				"    x.foo();\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Lp1/X;{0}+Ljava/lang/Object;>;.foo()V");
	}

	/*
	 * Ensures that a parameterized method binding (where the parameter is a super wildcard) can be created using its key in ASTRequestor#createBindings.
	 */
	public void test040() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  void foo() {\n" +
				"  }\n" +
				"  void bar(X<? super Error> x) {\n" +
				"    x.foo();\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Lp1/X;{0}-Ljava/lang/Error;>;.foo()V");
	}

	/*
	 * Ensures that a parameterized method binding (where the parameters contain wildcards) can be created using its key in ASTRequestor#createBindings.
	 */
	public void test041() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T, U, V, W> {\n" +
				"  void foo() {\n" +
				"  }\n" +
				"  void bar(X<? super Error, ?, String, ? extends Object> x) {\n" +
				"    x.foo();\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Lp1/X;{0}-Ljava/lang/Error;Lp1/X;{1}*Ljava/lang/String;Lp1/X;{2}+Ljava/lang/Object;>;.foo()V");
	}

	/*
	 * Ensures that requesting 2 bindings and an AST for the same compilation unit reports the 2 bindings.
	 */
	public void test042() throws CoreException {
		ICompilationUnit workingCopy = null;
		try {
			workingCopy = getWorkingCopy(
				"/P/X.java",
				"public class X {\n" +
				"  int field;\n" +
				"}"
			);
			BindingRequestor requestor = new BindingRequestor();
			String[] bindingKeys =
				new String[] {
					"LX;",
					"LX;.field)I"
				};
			resolveASTs(
				new ICompilationUnit[] {workingCopy},
				bindingKeys,
				requestor,
				getJavaProject("P"),
				workingCopy.getOwner()
			);
			assertBindingsEqual(
				"LX;\n" +
				"LX;.field)I",
				requestor.getBindings(bindingKeys));
		} finally {
			if (workingCopy != null)
				workingCopy.discardWorkingCopy();
		}
	}

	/*
	 * Ensures that a source parameterized type binding (where the parameters contain wildcard with a super bound) can be created using its key in ASTRequestor#createBindings.
	 */
	public void test043() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  X<? super T> field;\n" +
				"}",
			},
			"Lp1/X<Lp1/X;{0}-Lp1/X;:TT;>;");
	}

	/*
	 * Ensures that a binary parameterized type binding (where the parameters contain wildcard with a super bound) can be created using its key in ASTRequestor#createBindings.
	 * (regression test for 83499 ClassCastException when restoring ITypeBinding from key)
	 */
	public void test044() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<E> {\n" +
				"  Class<? extends E> field;\n" +
				"}",
			},
			"Ljava/lang/Class<Lp1/X;{0}+Lp1/X;:TE;>;");
	}

	/*
	 * Ensures that restoring a second key that references a type in a first key doesn't throw a NPE
	 * (regression test for bug 83499 NPE when restoring ITypeBinding from key)
	 */
	public void test045() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"}",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y<E> {\n" +
				"}"
			},
			new String[] {
				"Lp1/X;",
				"Lp1/Y<Lp1/Y;{0}+Lp1/X;>;"
			}
		);
		assertBindingsEqual(
			"Lp1/X;\n" +
			"Lp1/Y<Lp1/Y;{0}+Lp1/X;>;",
			bindings);
	}

	/*
	 * Ensures that a binary array parameterized type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test046() throws CoreException {
		assertBindingCreated(
			new String[] {},
			"[Ljava/lang/Class<Ljava/lang/Object;>;");
	}

	/*
	 * Ensures that the null type binding can be created using its key in batch creation.
	 */
	public void test047() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"N"});
		assertBindingsEqual(
				"N",
				bindings);
	}

	/*
	 * Ensures that a binary array type binding can be created using its key in batch creation.
	 */
	public void test048() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"[Ljava/lang/Object;"});
		assertBindingsEqual(
				"[Ljava/lang/Object;",
				bindings);
	}

	/*
	 * Ensures that a type variable binding can be created using its key in batch creation.
	 */
	public void test049() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"Ljava/lang/Class<TT;>;:TT;"});
		assertBindingsEqual(
				"Ljava/lang/Class;:TT;",
				bindings);
	}

	/*
	 * Ensures that a parameterized type binding with a wildcard that extends an array the can be created using its key in batch creation.
	 */
	public void test050() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"Ljava/lang/Class<Ljava/lang/Class<TT;>;{0}+[Ljava/lang/Object;>;"});
		assertBindingsEqual(
				"Ljava/lang/Class<Ljava/lang/Class;{0}+[Ljava/lang/Object;>;",
				bindings);
	}

	/*
	 * Ensures that attempting to create a top level type that doesn't exist using its key i in batch creation.
	 * returns null.
	 */
	public void test051() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"Lp1/DoesNotExist;"});
		assertBindingsEqual(
				"<null>",
				bindings);
	}

	/*
	 * Ensures that a secondary type binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test052() throws CoreException {
		try {
			createFolder("/P/p1");
			createFile(
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"}\n" +
				"class Y {\n" +
				"}"
			);
			assertBindingCreated(new String[] {}, "Lp1/X~Y;");
		} finally {
			deleteFolder("/P/p1");
		}
	}

	/*
	 * Ensures that an anonymous type binding coming from secondary type can be created using its key in ASTRequestor#createBindings.
	 */
	public void test053() throws CoreException {
		try {
			createFolder("/P/p1");
			createFile(
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"}\n" +
				"class Y {\n" +
				"  void foo() {\n" +
				"    new Y() {};\n" +
				"  }\n" +
				"}"
			);
			assertBindingCreated(new String[] {}, "Lp1/X~Y$64;");
		} finally {
			deleteFolder("/P/p1");
		}
	}

	/*
	 * Ensures that an anonymous type binding inside a local type can be retrieved using its key.
	 */
	public void test054() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    class Y {\n" +
				"      void bar() {\n" +
				"        new X() /*start*/{\n" +
				"        }/*end*/;" +
				"      }\n" +
				"    }\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X$89;"
		);
	}

	/*
	 * Ensures that a parameterized generic method binding can be created using its key in ASTRequestor#createBindings.
	 */
	public void test055() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"  <U> void foo(U u) {\n" +
				"  }\n" +
				"  void bar() {\n" +
				"    /*start*/new X<String>().foo(new X() {})/*end*/;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X<Ljava/lang/String;>;.foo<U:Ljava/lang/Object;>(TU;)V%<Lp1/X$101;>"
		);
	}

	/*
	 * Ensures that creating a binary member type binding returns the correct binding
	 * (regression test for bug 86967 [1.5][dom] NPE in BindingKeyResolver for multi-level parameterized type binding)
	 */
	public void test056() throws CoreException, IOException {
		try {
			IJavaProject project = createJavaProject("BinaryProject", new String[0], new String[] {"JCL15_LIB"}, "", "1.5");
			addLibrary(project, "lib.jar", "src.zip", new String[] {
				"/BinaryProject/p/X.java",
				"package p;\n" +
				"public class X<K, V> {\n" +
				"  public class Y<K1, V1> {\n" +
				"  }\n" +
				"}"
			}, "1.5");
			ITypeBinding[] bindings = createTypeBindings(new String[0], new String[] {
				"Lp/X<>.Y<Lp/X;:TK;Lp/X;:TV;>;"
			}, project);
			assertBindingsEqual(
				"Lp/X<>.Y<Lp/X;:TK;Lp/X;:TV;>;",
				bindings);
		} finally {
			deleteProject("BinaryProject");
		}
	}

	/*
	 * Ensures that creating a missing binary member type binding doesn't throw a NPE
	 * (regression test for bug 86967 [1.5][dom] NPE in BindingKeyResolver for multi-level parameterized type binding)
	 */
	public void test057() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {},
			new String[] {"Lp/Missing$Member;"});
		assertBindingsEqual(
			"<null>",
			bindings);
	}

	/*
	 * Ensures that a type parameter binding can be created using its key in batch creation.
	 * (regression test for bug 87050 ASTParser#createASTs(..) cannot resolve method type parameter binding from key)
	 */
	public void test058() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  </*start*/T/*end*/> void foo(T t) {\n" +
				"  }" +
				"}",
			},
			"Lp1/X;.foo<T:Ljava/lang/Object;>(TT;)V:TT;");
	}

	/*
	 * Ensures that a capture binding can be created using its key in batch creation.
	 */
	public void test059() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<T> {\n" +
				"    Object foo(X<?> list) {\n" +
				"       return /*start*/list.get()/*end*/;\n" +
				"    }\n" +
				"    T get() {\n" +
				"    	return null;\n" +
				"    }\n" +
				"}",
			},
			"Lp1/X;&!Lp1/X;{0}*77;"
		);
	}

	/*
	 * Ensures that a capture binding can be created using its key in batch creation.
	 */
	public void test060() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/xy/Cap.java",
				"package xy;\n" +
				"import java.util.Vector;\n" +
				"public class Cap {\n" +
				"	{\n" +
				"		Vector<?> v= null;\n" +
				"		/*start*/v.get(0)/*end*/;\n" +
				"	}\n" +
				"}",
				"/P/java/util/Vector.java",
				"package java.util;\n" +
				"public class Vector<T> {\n" +
				"  public T get(int i) {\n" +
				"    return null;\n" +
				"  }\n" +
				"}"
			},
			"Lxy/Cap;&!Ljava/util/Vector;{0}*82;"
		);
	}

	/*
	 * Ensures that a generic constructor binding can be created using its key in batch creation.
	 */
	public void test061() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"    /*start*/<T> X() {\n" +
				"    }/*end*/\n" +
				"}",
			},
			"Lp1/X;.<T:Ljava/lang/Object;>()V"
		);
	}

	/*
	 * Ensures that an array binding whose leaf type is a type variable binding can be created using its key in batch creation.
	 * (regression test for bug 94206 CCE in BindingKeyResolver when restoring array type of method type parameter)
	 */
	public void test062() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  <T> /*start*/T[]/*end*/ foo(T[] a) {\n" +
				"    return null;\n" +
				"  }\n" +
				"}",
			},
			"[Lp1/X;.foo<T:Ljava/lang/Object;>([TT;)[TT;:TT;"
		);
	}

	/*
	 * Ensures that a raw method binding can be created using its key in batch creation.
	 * (regression test for bug 87749 different IMethodBindings of generic method have equal getKey())
	 */
	public void test063() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"	public static <T extends Y<? super T>> void foo(Z<T> z) {\n" +
				"    }\n" +
				"    /**\n" +
				"     * @see #foo(Z)\n" +
				"     */\n" +
				"    void bar() {\n" +
				"        /*start*/foo(new W())/*end*/;\n" +
				"    }\n" +
				"}\n" +
				"class Y<T> {\n" +
				"}\n" +
				"class Z<T> {\n" +
				"}\n" +
				"class W<T> extends Z<T> {\n" +
				"}",
			},
			"Lp1/X;.foo<T:Lp1/Y<-TT;>;>(Lp1/Z<TT;>;)V%<Lp1/X~Y<Lp1/X~Y;{0}-Lp1/X~Y<Lp1/X~Y;{0}-Lp1/X;:2TT;>;>;>"
		);
	}

	/*
	 * Ensures that a raw method binding can be created using its key in batch creation.
	 * (regression test for bug 87749 different IMethodBindings of generic method have equal getKey())
	 */
	public void test063a() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<U extends X<T>> {\n" +
				"	public void foo(Z<U> z) {\n" +
				"    }\n" +
				"    /**\n" +
				"     * @see #foo(Z)\n" +
				"     */\n" +
				"    static void bar(X x) {\n" +
				"        /*start*/x.foo(new W())/*end*/;\n" +
				"    }\n" +
				"}\n" +
				"class Y<T> {\n" +
				"}\n" +
				"class Z<T> {\n" +
				"}\n" +
				"class W<T> extends Z<T> {\n" +
				"}",
			},
			"Lp1/X<>;.foo(Lp1/Z;)V"
		);
	}
	
	/*
	 * Ensures that a parameterized type binding with a capture binding in its arguments can be created using its key in batch creation.
	 * (regression test for bug 94092 ASTParser#createASTs(..) restores wrong bindings from capture keys)
	 */
	public void test064() throws CoreException {
		assertRequestedBindingsFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"/*start1*/public class X {\n" +
				"	Object o= null;\n" +
				"	Y<?> field;\n" +
				"	void foo() {\n" +
				"		/*start2*/o = field/*end2*/;\n" +
				"	}\n" +
				"}/*end1*/\n",
				"/P/p1/Y.java",
				"package p1;\n" +
				"public class Y<T> {\n" +
				"}",
			},
			new String[] {
				"Lp1/X;",
				"Lp1/X;&Lp1/Y<!Lp1/Y;{0}*83;>;",
			}
		);
	}

	/*
	 * Ensures that a parameterized type binding with a type variable of the current's method in its arguments can be created using its key in batch creation.
	 * (regression test for bug 97902 NPE on Open Declaration on reference to generic type)
	 */
	public void test065() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  <T> void foo(/*start*/Y<T>/*end*/ y) {\n" +
				"  }\n" +
				"}\n" +
				"class Y<E> {\n" +
				"}",
			},
			"Lp1/X~Y<Lp1/X;:1TT;>;"
		);
	}

	/*
	 * Ensures that the compilation with a owner is used instead of a primary working copy when looking up a type.
	 * (regression test for bug 97542 ASTParser#createASTs does not correctly resolve bindings in working copies)
	 */
	public void test066() throws CoreException {
		ICompilationUnit primaryWorkingCopy = null;
		ICompilationUnit ownedWorkingcopy = null;
		try {
			// primary working copy with no method foo()
			primaryWorkingCopy = getCompilationUnit("/P/p1/X.java");
			primaryWorkingCopy.becomeWorkingCopy(null/*no progress*/);
			primaryWorkingCopy.getBuffer().setContents(
				"package p1;\n" +
				"public class X {\n" +
				"}"
			);
			primaryWorkingCopy.reconcile(ICompilationUnit.NO_AST, false, null, null);

			// working copy for the test's owner with a method foo()
			ownedWorkingcopy = getWorkingCopy(
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {}\n" +
				"}",
				this.owner
			);

			// create bindings
			assertRequestedBindingFound(
				new String[] {
					"/P/p1/Y.java",
					"package p1;\n" +
					"public class Y {\n" +
					"  void bar() {\n" +
					"    /*start*/new X().foo()/*end*/;\n" +
					"}",
				},
				"Lp1/X;.foo()V"
			);
		} finally {
			if (primaryWorkingCopy != null)
				primaryWorkingCopy.discardWorkingCopy();
			if (ownedWorkingcopy != null)
				ownedWorkingcopy.discardWorkingCopy();
		}
	}

	/*
	 * Ensures that the declaring class of a member parameterized type binding with a raw enclosing type is correct
	 */
	public void test067() throws CoreException {
		ITypeBinding[] bindings = createTypeBindings(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X<K, V> {\n" +
				"  public class Y<K1, V1> {\n" +
				"  }\n" +
				"  /*start*/Y<K, V>/*end*/ field;\n" +
				"}"
			},
			new String[] {"Lp1/X$Y<Lp1/X;:TK;Lp1/X;:TV;>;"}
		);
		assertBindingEquals(
			"Lp1/X<>;",
			bindings.length == 0 ? null : bindings[0].getDeclaringClass()
		);
	}

	/*
	 * Ensures that a raw member type can be created using its key in batch creation.
	 */
	public void test068() throws CoreException, IOException {
		try {
			IJavaProject project = createJavaProject("P1", new String[] {""}, new String[] {"JCL15_LIB"}, "", "1.5");
			addLibrary(project, "lib.jar", "src.zip", new String[] {
				"/P1/p/X.java",
				"package p;\n" +
				"public class X<K, V> {\n" +
				"  public static class Member<K1, V1> {\n" +
				"  }\n" +
				"}",
				"/P1/p/Y.java",
				"package p;\n" +
				"public class Y {\n" +
				"  void foo(X.Member x) {\n" +
				"  }\n" +
				"}",
			}, "1.5");
			assertRequestedBindingFound(
				new String[] {
					"/P1/p1/Z.java",
					"package p1;\n" +
					"public class Z extends p.Y {\n" +
					"  /*start*/p.X.Member/*end*/ field;\n" +
					"}"
				},
				"Lp/X$Member<>;"
			);
		} finally {
			deleteProject("P1");
		}
	}

	/*
	 * Ensures that requesting a CU needing a constant in a previously processed CU doesn't throw an NPE
	 * (regression test for bug 111822 DOMParser.createASTs() NPE at FieldReference.getConstantFor(FieldReference.java:408))
	 */
	public void test069() throws CoreException {
		this.workingCopies = createWorkingCopies(new String[] {
			"/P/pkg/RefAnnoAndClassWithAnno.java",
			"package pkg;\n" +
			"public class RefMyAnnoAndClassWithAnno {\n" +
			"	final Class anno = MyAnno.class;\n" +
			"	final Class withAnno = ClassWithAnnotation.class;\n" +
			"}",
			"/P/pkg/MyAnno.java",
			"package pkg;\n" +
			"public @interface MyAnno {\n" +
			"	public enum EnumColor{\n" +
			"		BLUE, RED, WHITE;\n" +
			"	}\n" +
			"	EnumColor aEnum();\n" +
			"}",
			"/P/pkg/ClassWithAnnotation.java",
			"package pkg;\n" +
			"import pkg.MyAnno.EnumColor;\n" +
			"@MyAnno(aEnum = EnumColor.BLUE)\n" +
			"public class ClassWithAnnotation {}"
		});
		String key = BindingKey.createTypeBindingKey("pkg.RefMyAnnoAndClassWithAnno");
		BindingResolver resolver = new BindingResolver(new MarkerInfo[0]);
		resolveASTs(new ICompilationUnit[0],  new String[] {key}, resolver, getJavaProject("P"), this.owner);
		assertStringsEqual(
			"Unexpected bindings",
			"Lpkg/RefAnnoAndClassWithAnno~RefMyAnnoAndClassWithAnno;\n",
			resolver.getFoundKeys());
	}

	/*
	 * Ensures that unrequested compilation units are not resolved
	 * (regression test for bug 114935 ASTParser.createASTs parses more CUs then required)
	 */
	public void test070() throws CoreException {
		MarkerInfo[] markerInfos = createMarkerInfos(new String[] {
			"/P/p1/X.java",
			"package p1;\n" +
			"public class X extends /*start*/Y/*end*/ {\n" +
			"}",
			"/P/p1/Y.java",
			"package p1;\n" +
			"public class Y {\n" +
			"  static final int CONST = 2 + 3;\n" +
			"}",
		});
		this.workingCopies = createWorkingCopies(markerInfos, this.owner);
		TestASTRequestor requestor = new TestASTRequestor();
		resolveASTs(new ICompilationUnit[] {this.workingCopies[0]}, requestor);

		// get the binding for Y
		Type y = (Type) findNode((CompilationUnit) requestor.asts.get(0), markerInfos[0]);
		ITypeBinding yBinding = y.resolveBinding();

		// ensure that the fields for Y are not resolved
		assertBindingsEqual("", yBinding.getDeclaredFields());
	}

	/*
	 * Ensures that unrequested compilation units are not resolved
	 * (regression test for bug 117018 IVariableBinding#getConstantValue() could be lazy resolved)
	 */
	public void test071() throws CoreException {
		final MarkerInfo[] markerInfos = createMarkerInfos(new String[] {
			"/P/p1/X.java",
			"package p1;\n" +
			"public class X extends /*start*/Y/*end*/ {\n" +
			"}",
			"/P/p1/Y.java",
			"package p1;\n" +
			"public class Y {\n" +
			"  static final int CONST = 2 + 3;\n" +
			"}",
		});
		this.workingCopies = createWorkingCopies(markerInfos, this.owner);
		class Requestor extends TestASTRequestor {
			Object constantValue = null;
			public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
				super.acceptAST(source, ast);
				Type y = (Type) findNode(ast, markerInfos[0]);
				ITypeBinding typeBinding = y.resolveBinding();
				IVariableBinding fieldBinding = typeBinding.getDeclaredFields()[0];
				this.constantValue = fieldBinding.getConstantValue();
			}
		}
		Requestor requestor = new Requestor();
		resolveASTs(new ICompilationUnit[] {this.workingCopies[0]}, requestor);

		assertEquals("Unexpected constant value", 5, requestor.constantValue);
	}

	/*
	 * Ensures that the declaring method of a local variable binding retrieved using its key
	 * is not null
	 * (regression test for bug 129804 Local variable bindings from ASTParser#createASTs(.., String[], .., ..) have no declaring method)
	 */
	public void test072() throws CoreException {
		IVariableBinding[] bindings = createVariableBindings(
			new String[] {
				"/P/X.java",
				"public class X {\n" +
				"    void m() {\n" +
				"        Object o;\n" +
				"    }\n" +
				"}"
			},
			new String[] {
				"LX;.m()V#o"
			}
		);
		assertBindingEquals(
			"LX;.m()V",
			bindings[0].getDeclaringMethod());
	}

// https://bugs.eclipse.org/bugs/show_bug.cgi?id=159631
public void test073() throws CoreException, IOException {
	try {
		IJavaProject project = createJavaProject("P072", new String[] {}, Util.getJavaClassLibs(), "", "1.5");
		ICompilationUnit compilationUnits[] = new ICompilationUnit[3];
		compilationUnits[0] = getWorkingCopy(
			"P072/X.java",
			"public class X {\n" +
			"  @Override" +
			"  public boolean equals(Object o) {\n" +
			"    return true;\n" +
			"  }\n" +
			"}");
		compilationUnits[1] = getWorkingCopy(
			"P072/Y.java",
			"public class Y extends X {\n" +
			"}");
		compilationUnits[2] = getWorkingCopy(
			"P072/Z.java",
			"public class Z {\n" +
			"  Y m;\n" +
			"  boolean foo(Object p) {\n" +
			"    return this.m.equals(p);\n" +
			"  }\n" +
			"}");
		ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(project);
		class Requestor extends ASTRequestor {
		}
		parser.createASTs(compilationUnits, new String[0], new Requestor(), null);
		// will throw an unexpected NPE, until the bug is fixed
	} finally {
		deleteProject("P072");
	}
}

/**
 * @bug 155003: [model] Missing exception types / wrong signature?
 * @test Ensure that thrown exceptions are added in method unique key (not in signature)
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=155003"
 */
public void test074_Bug155003() throws CoreException {
	assertBindingCreated(
		new String[] {
			"/P/X.java",
			"public class X {\n" +
			"    public void foo() throws InterruptedException, IllegalMonitorStateException {\n" +
			"    }\n" +
			"    void test() throws InterruptedException, IllegalMonitorStateException {\n" +
			"    	/*start*/foo()/*end*/;\n" +
			"    }\n" +
			"}",
		},
		"LX;.foo()V|Ljava/lang/InterruptedException;|Ljava/lang/IllegalMonitorStateException;"
	);
	String content = "public class X {\n" +
			"    public void foo() throws InterruptedException, IllegalMonitorStateException {\n" +
			"    }\n" +
			"    void test() throws InterruptedException, IllegalMonitorStateException {\n" +
			"    	/*start*/foo()/*end*/;\n" +
			"    }\n" +
			"}";
	this.workingCopies = createWorkingCopies(new String[] { "/P/X.java", content }, true /*resolve*/);
	ASTNode node = buildAST(content, this.workingCopies[0]);
	assertEquals("Invalid node type!", ASTNode.METHOD_INVOCATION, node.getNodeType());
	IBinding binding = resolveBinding(node);
	BindingKey bindingKey = new BindingKey(binding.getKey());
	assertStringsEqual("Unexpected thrown exceptions",
		"Ljava.lang.InterruptedException;\n" +
		"Ljava.lang.IllegalMonitorStateException;\n",
		bindingKey.getThrownExceptions()
	);
}
public void test075_Bug155003() throws CoreException {
	String content = "public class X<T> {\n" +
		"	<U extends Exception> X<T> foo(X<T> x) throws RuntimeException, U {\n" +
		"		return null;\n" +
		"	}\n" +
		"	void test() throws Exception {\n" +
		"		/*start*/foo(this)/*end*/;\n" +
		"	}\n" +
		"}";
	this.workingCopies = createWorkingCopies(new String[] { "/P/X.java", content }, true /*resolve*/);
	ASTNode node = buildAST(content, this.workingCopies[0]);
	assertEquals("Invalid node type!", ASTNode.METHOD_INVOCATION, node.getNodeType());
	IBinding binding = resolveBinding(node);
	BindingKey bindingKey = new BindingKey(binding.getKey());
	assertStringsEqual("Unexpected thrown exceptions",
		"Ljava.lang.RuntimeException;\n" +
		"TU;\n",
		bindingKey.getThrownExceptions()
	);
}
public void test076_Bug155003() throws CoreException {
	String content = "public class X<T> {\n" +
		"	<K, V> V bar(K key, V value) throws Exception {\n" +
		"		return value;\n" +
		"	}\n" +
		"	void test() throws Exception {\n" +
		"		/*start*/bar(\"\", \"\")/*end*/;\n" +
		"	}\n" +
		"}";
	this.workingCopies = createWorkingCopies(new String[] { "/P/X.java", content }, true /*resolve*/);
	ASTNode node = buildAST(content, this.workingCopies[0]);
	assertEquals("Invalid node type!", ASTNode.METHOD_INVOCATION, node.getNodeType());
	IBinding binding = resolveBinding(node);
	BindingKey bindingKey = new BindingKey(binding.getKey());
	assertStringsEqual("Unexpected thrown exceptions",
		"Ljava.lang.Exception;\n",
		bindingKey.getThrownExceptions()
	);
}

/**
 * @bug 163647: [model] Thrown exceptions are not found in method binding key which have a capture as declaring class
 * @test Ensure that thrown exceptions are added in method unique key (not in signature)
 * 			even when declaring class is a capture
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=163647"
 */
public void test077_Bug163647() throws CoreException {
	String content = 	"public class Test {\n" +
		"    public X<? extends Object> getX() { return null; }\n" +
		"    public void bar() {\n" +
		"		try {\n" +
		"			/*start*/getX().foo()/*end*/;\n" +
		"		} catch (Exception e) {\n" +
		"			// skip\n" +
		"		}\n" +
		"    }\n" +
		"}\n" +
		"class X<T> {\n" +
		"    public void foo() throws CloneNotSupportedException, IllegalMonitorStateException, InterruptedException {\n" +
		"    }\n" +
		"}";
	this.workingCopies = createWorkingCopies(new String[] { "/P/Test.java", content }, true /*resolve*/);
	ASTNode node = buildAST(content, this.workingCopies[0]);
	assertEquals("Invalid node type!", ASTNode.METHOD_INVOCATION, node.getNodeType());
	IBinding binding = resolveBinding(node);
	BindingKey bindingKey = new BindingKey(binding.getKey());
	assertStringsEqual("Unexpected thrown exceptions",
		"Ljava.lang.CloneNotSupportedException;\n" +
		"Ljava.lang.IllegalMonitorStateException;\n" +
		"Ljava.lang.InterruptedException;\n",
		bindingKey.getThrownExceptions()
	);
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=152060
public void test078() throws CoreException, IOException {
	try {
		IJavaProject project = createJavaProject("P078", new String[] {}, Util.getJavaClassLibs(), "", "1.5");
		ICompilationUnit compilationUnits[] = new ICompilationUnit[1];
		compilationUnits[0] = getWorkingCopy(
			"P078/Test.java",
			"import java.util.*;\n" +
			"public class Test {\n" +
			"        public interface ExtraIterator<T> extends Iterator {\n" +
			"                public void extra();\n" +
			"        }\n" +
			"        public class Test2<T> implements ExtraIterator<T> {\n" +
			"            public boolean hasNext() {\n" +
			"                return false;\n" +
			"            }\n" +
			"            public T next() {\n" +
			"                return null;\n" +
			"            }\n" +
			"            public void remove() {\n" +
			"            }\n" +
			"            public void extra() {\n" +
			"            }\n" +
			"        }\n" +
			"}");
		ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(project);
       	final IBinding[] bindings = new IBinding[1];
		final String key = "LTest$ExtraIterator<>;";
		parser.createASTs(
			compilationUnits,
			new String[] {
				key
			},
			new ASTRequestor() {
                public void acceptAST(ICompilationUnit source, CompilationUnit localAst) {
                	// do nothing
                }
                public void acceptBinding(String bindingKey, IBinding binding) {
                	if (key.equals(bindingKey)) {
                		bindings[0] = binding;
                 	}
                }
			},
			null);
		IBinding binding = bindings[0];
		assertNotNull("Should not be null", binding);
		assertEquals("Not a type binding", IBinding.TYPE, binding.getKind());
		ITypeBinding typeBinding = (ITypeBinding) binding;
		assertEquals("Wrong name", "Test.ExtraIterator", typeBinding.getQualifiedName());
		assertTrue("Not a raw type", typeBinding.isRawType());
	} finally {
		deleteProject("P078");
	}
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=152060
public void test079() throws CoreException, IOException {
	try {
		IJavaProject project = createJavaProject("P079", new String[] {"src"}, Util.getJavaClassLibs(), "bin", "1.5");
		createFolder("/P079/src/test");
		createFile("/P079/src/test/Test.java",
				"package test;\n" +
				"import java.util.*;\n" +
				"interface ExtraIterator<T> extends Iterator {\n" +
				"        public void extra();\n" +
				"}\n" +
				"public class Test<T> implements ExtraIterator<T> {\n" +
				"    public boolean hasNext() {\n" +
				"        return false;\n" +
				"    }\n" +
				"    public T next() {\n" +
				"        return null;\n" +
				"    }\n" +
				"    public void remove() {\n" +
				"    }\n" +
				"    public void extra() {\n" +
				"    }\n" +
				"}");
		ICompilationUnit compilationUnits[] = new ICompilationUnit[1];
		compilationUnits[0] = getCompilationUnit("P079", "src", "test", "Test.java");
		ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(project);
		final IBinding[] bindings = new IBinding[1];
		final String key = "Ltest/Test~ExtraIterator<>;";
		parser.createASTs(
				compilationUnits,
				new String[] {
						key
				},
				new ASTRequestor() {
					public void acceptAST(ICompilationUnit source, CompilationUnit localAst) {
						// do nothing
					}
					public void acceptBinding(String bindingKey, IBinding binding) {
						if (key.equals(bindingKey)) {
							bindings[0] = binding;
						}
					}
				},
				null);
		IBinding binding = bindings[0];
		assertNotNull("Should not be null", binding);
		assertEquals("Not a type binding", IBinding.TYPE, binding.getKind());
		ITypeBinding typeBinding = (ITypeBinding) binding;
		assertEquals("Wrong type", "test.ExtraIterator", typeBinding.getQualifiedName());
	} finally {
		deleteProject("P079");
	}
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=152060
public void test080() throws CoreException, IOException {
	final String projectName = "P080";
	try {
		IJavaProject project = createJavaProject(projectName, new String[] {"src"}, Util.getJavaClassLibs(), "bin", "1.5");
		createFolder("/" + projectName + "/src/test");
		createFile("/" + projectName + "/src/test/Test.java",
				"package test;\n" +
				"import java.util.*;\n" +
				"public class Test {\n" +
				"        public interface ExtraIterator<T> extends Iterator {\n" +
				"                public void extra();\n" +
				"        }\n" +
				"        public class Test2<T> implements ExtraIterator<T> {\n" +
				"            public boolean hasNext() {\n" +
				"                return false;\n" +
				"            }\n" +
				"            public T next() {\n" +
				"                return null;\n" +
				"            }\n" +
				"            public void remove() {\n" +
				"            }\n" +
				"            public void extra() {\n" +
				"            }\n" +
				"        }\n" +
				"}");
		ICompilationUnit compilationUnits[] = new ICompilationUnit[1];
		compilationUnits[0] = getCompilationUnit(projectName, "src", "test", "Test.java");
		ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(project);
       	final IBinding[] bindings = new IBinding[1];
		final String key = "Ltest/Test$ExtraIterator<>;";
		parser.createASTs(
			compilationUnits,
			new String[] {
				key
			},
			new ASTRequestor() {
                public void acceptAST(ICompilationUnit source, CompilationUnit localAst) {
                	// do nothing
                }
                public void acceptBinding(String bindingKey, IBinding binding) {
                	if (key.equals(bindingKey)) {
                		bindings[0] = binding;
                 	}
                }
			},
			null);
		IBinding binding = bindings[0];
		assertNotNull("Should not be null", binding);
		assertEquals("Not a type binding", IBinding.TYPE, binding.getKind());
		ITypeBinding typeBinding = (ITypeBinding) binding;
		assertEquals("Wrong name", "test.Test.ExtraIterator", typeBinding.getQualifiedName());
		assertTrue("Not a raw type", typeBinding.isRawType());
	} finally {
		deleteProject(projectName);
	}
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=111529
public void test081() throws CoreException, IOException {
	final String projectName = "P081";
	try {
		IJavaProject javaProject = createJavaProject(projectName, new String[] {"src"}, Util.getJavaClassLibs(), "bin", "1.5");
		String typeName = "java.util.List<java.lang.Integer>";
		class BindingRequestor extends ASTRequestor {
			ITypeBinding _result = null;
			public void acceptBinding(String bindingKey, IBinding binding) {
				if (this._result == null && binding != null && binding.getKind() == IBinding.TYPE)
					this._result = (ITypeBinding) binding;
			}
		}
		String[] keys = new String[] {
			BindingKey.createTypeBindingKey(typeName)
		};
		final BindingRequestor requestor = new BindingRequestor();
		final ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(javaProject);
		// this doesn't really do a parse; it's a type lookup
		parser.createASTs(new ICompilationUnit[] {}, keys, requestor, null);
		ITypeBinding typeBinding = requestor._result;
		assertNotNull("No binding", typeBinding);
		assertTrue("Not a parameterized type binding", typeBinding.isParameterizedType());
	} finally {
		deleteProject(projectName);
	}
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=111529
public void test082() throws CoreException, IOException {
	final String projectName = "P082";
	try {
		IJavaProject javaProject = createJavaProject(projectName, new String[] {"src"}, Util.getJavaClassLibs(), "bin", "1.5");
		String typeName = "java.util.List<Integer>";
		class BindingRequestor extends ASTRequestor {
			ITypeBinding _result = null;
			public void acceptBinding(String bindingKey, IBinding binding) {
				if (this._result == null && binding != null && binding.getKind() == IBinding.TYPE)
					this._result = (ITypeBinding) binding;
			}
		}
		String[] keys = new String[] {
			BindingKey.createTypeBindingKey(typeName)
		};
		final BindingRequestor requestor = new BindingRequestor();
		final ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
		parser.setResolveBindings(true);
		parser.setProject(javaProject);
		// this doesn't really do a parse; it's a type lookup
		parser.createASTs(new ICompilationUnit[] {}, keys, requestor, null);
		ITypeBinding typeBinding = requestor._result;
		assertNull("Got a binding", typeBinding);
	} finally {
		deleteProject(projectName);
	}
}

	/*
	 * Ensures that a secondary type binding can be retrieved using its key, even if the primary type doesn't exist.
	 * (regression test for bug 177115 NullPointerException in BindingKeyResolver.consumeTypeVariable(...))
	 */
	public void test083() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"/*start*/class Y {\n" +
				"}/*end*/",
			},
			"Lp1/X~Y;");
	}

	/*
	 * Ensures that a duplicate local variable binding can be created using its key in ASTRequestor#createBindings
	 * (regression test for bug 149590 [model] bindings for duplicate local variables share same key)
	 */
	public void test084() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  void foo() {\n" +
				"    int i;\n" +
				"    int i;\n" +
				"  }\n" +
				"}",
			},
			"Lp1/X;.foo()V#i#1");
	}

	/*
	 * Ensures that an annotation binding can be retrieved using its key.
	 */
	public void test085() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"/*start*/@MyAnnot/*end*/\n" +
				"public class X {\n" +
				"}",
				"/P/p1/MyAnnot.java",
				"package p1;\n" +
				"public @interface MyAnnot {\n" +
				"}",
			},
			"Lp1/X;@Lp1/MyAnnot;");
	}

	/*
	 * Ensures that an annotation binding can be retrieved using its key.
	 */
	public void test086() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  /*start*/@MyAnnot/*end*/\n" +
				"  int field;\n" +
				"}",
				"/P/p1/MyAnnot.java",
				"package p1;\n" +
				"public @interface MyAnnot {\n" +
				"}",
			},
			"Lp1/X;.field)I@Lp1/MyAnnot;");
	}

	/*
	 * Ensures that an annotation binding can be retrieved using its key.
	 */
	public void test087() throws CoreException {
		assertRequestedBindingFound(
			new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  /*start*/@MyAnnot/*end*/\n" +
				"  void foo() {\n" +
				"  }\n" +
				"}",
				"/P/p1/MyAnnot.java",
				"package p1;\n" +
				"public @interface MyAnnot {\n" +
				"}",
			},
			"Lp1/X;.foo()V@Lp1/MyAnnot;");
	}

	/*
	 * Ensures that a parameterized type with 2 arguments referring to the same cu that contains an anonymous type with a non-default constructor
	 * can be created using its key in ASTRequestor#createBindings
	 * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=236445 )
	 */
	public void test088() throws CoreException {
		assertBindingCreated(
			new String[] {
				"/P/A.java",
				"public class A {\n" +
				"	public void foo(C c) {\n" +
				"		c.bar(B //|<---Ctrl+Space after B\n" +
				"	}\n" +
				"}\n" +
				"class B<V, E> {\n" +
				"}",
				"/P/C.java",
				"public class C {\n" +
				"	public <V, E> void bar(B<V, E> code) {\n" +
				"		new D(null) {};  \n" +
				"	}\n" +
				"}\n" +
				"class D {\n" +
				"	D(Object o) {}\n" +
				"}"
			},
			"LA~B<LC;:1TV;LC;:1TE;>;");
	}
	
	public void testIgnoreMethodBodies1() throws CoreException {
		this.workingCopies = createWorkingCopies(new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  public int foo() {\n" +
				"    int i = 0;\n" + 
				"  }\n" +
				"  public int bar() {\n" +
				"    int i = 0;\n" + 
				"    new X() /*start*/{\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			});
			TestASTRequestor requestor = new TestASTRequestor();
			ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
			parser.setIgnoreMethodBodies(true);
			parser.createASTs(this.workingCopies, new String[] {}, requestor, null);
			// statement declaring i should not be in the AST
			assertASTNodesEqual(
					"package p1;\n" +
					"public class X {\n" +
					"  public int foo(){\n" +
					"  }\n" +
					"  public int bar(){\n" +
					"  }\n" +
					"}\n" +
					"\n",
					requestor.asts
				);
	}
	public void testIgnoreMethodBodies2() throws CoreException {
		this.workingCopies = createWorkingCopies(new String[] {
				"/P/p1/X.java",
				"package p1;\n" +
				"public class X {\n" +
				"  public int foo() {\n" +
				"    int i = 0;\n" + 
				"  }\n" +
				"  public int bar() {\n" +
				"    int i = 0;\n" + 
				"    new X() /*start*/{\n" +
				"    }/*end*/;" +
				"  }\n" +
				"}",
			});
			TestASTRequestor requestor = new TestASTRequestor();
			ASTParser parser = ASTParser.newParser(JLS3_INTERNAL);
			parser.setIgnoreMethodBodies(true);
			parser.setResolveBindings(true);
			parser.setProject(getJavaProject("P"));
			parser.createASTs(this.workingCopies, new String[] {}, requestor, null);
			// statement declaring i should not be in the AST
			assertASTNodesEqual(
					"package p1;\n" +
					"public class X {\n" +
					"  public int foo(){\n" +
					"  }\n" +
					"  public int bar(){\n" +
					"  }\n" +
					"}\n" +
					"\n",
					requestor.asts
				);
	}
}
