/*******************************************************************************
 * Copyright (c) 2000, 2009 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.model;

import java.io.IOException;

import junit.framework.Test;

import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.core.tests.model.AbstractJavaSearchTests.JavaSearchResultCollector;
import org.eclipse.jdt.core.tests.model.AbstractJavaSearchTests.TypeNameMatchCollector;
import org.eclipse.jdt.internal.core.search.matching.PatternLocator;

/**
 * Tests the Java search engine accross multiple projects.
 */
public class JavaSearchMultipleProjectsTests extends ModifyingResourceTests implements IJavaSearchConstants {
	private final static int UI_DECLARATIONS = DECLARATIONS|IGNORE_DECLARING_TYPE|IGNORE_RETURN_TYPE;
public JavaSearchMultipleProjectsTests(String name) {
	super(name);
}
public static Test suite() {
	return buildModelTestSuite(JavaSearchMultipleProjectsTests.class);
}
// Use this static initializer to specify subset for tests
// All specified tests which do not belong to the class are skipped...
static {
//	TESTS_NAMES = new String[] { "testJavaSearchScopeBug101426" };
//	TESTS_NUMBERS = new int[] { 101426 };
//	TESTS_RANGE = new int[] { 16, -1 };
//	TESTS_PREFIX = "testScopeEncloses";
}

/**
 * Field occurences in 2 working copies within 2 projects (one prereq this other one).
 * (regression test for bug 41534 incorrect shadowing reported by rename [refactoring])
 */
public void testFieldOccurencesInWorkingCopies() throws CoreException {
	ICompilationUnit wc1 = null, wc2 = null;
	try {
		// setup project P1
		IJavaProject p1 = createJavaProject("P1");
		createFolder("/P1/p1");
		createFile(
			"/P1/p1/X.java",
			"package p1;\n" +
			"public class X {\n" +
			"    public static int FOO;\n" +
			"}"
		);

		// setup project P2
		IJavaProject p2 = createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P1"}, "");
		createFolder("/P2/p2");
		createFile(
			"/P2/p2/Y.java",
			"package p2;\n" +
			"import p1.X;\n" +
			"public class Y {\n" +
			"    int bar() {\n" +
			"      return X.FOO;\n" +
			"}"
		);

		// create working copies and rename X.FOO to X.BAR in these working copies
		wc1 = getCompilationUnit("P1/p1/X.java").getWorkingCopy(null);
		wc1.getBuffer().setContents(
			"package p1;\n" +
			"public class X {\n" +
			"    public static int BAR;\n" +
			"}"
		);
		wc1.reconcile(ICompilationUnit.NO_AST, false, null, null);
		wc2 = getCompilationUnit("P2/p2/Y.java").getWorkingCopy(null);
		wc2.getBuffer().setContents(
			"package p2;\n" +
			"import p1.X;\n" +
			"public class Y {\n" +
			"    int bar() {\n" +
			"      return X.BAR;\n" +
			"}"
		);

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		IField field = wc1.getType("X").getField("BAR");
		SearchPattern pattern = SearchPattern.createPattern(field, ALL_OCCURRENCES);
		new SearchEngine(new ICompilationUnit[] {wc1, wc2}).search(
			pattern,
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			scope,
			resultCollector,
			null);
		assertEquals(
			"Unexpected occurences of field p1.X.BAR",
			"p1/X.java [in P1] p1.X.BAR [BAR]\n" +
			"p2/Y.java [in P2] int p2.Y.bar() [BAR]",
			resultCollector.toString());
	} finally {
		if (wc1 != null) {
			wc1.discardWorkingCopy();
		}
		if (wc2 != null) {
			wc2.discardWorkingCopy();
		}
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Search for references in a hierarchy should find matches in super type.
 * (regression test for bug 31748 [search] search for reference is broken 2.1 M5)
 */
public void testHierarchyScope1() throws CoreException {
	try {
		createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/X.java",
			"package p;\n" +
			"public class X {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"	void bar() {\n" +
			"		foo();\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P1"}, "");
		createFile(
			"/P2/Y.java",
			"import p.X;\n" +
			"public class Y extends X {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"}"
		);
		ICompilationUnit cu = getCompilationUnit("/P2/Y.java");
		IType type = cu.getType("Y");
		IMethod method = type.getMethod("foo", new String[] {});
		IJavaSearchScope scope = SearchEngine.createHierarchyScope(type);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"p/X.java [in P1] void p.X.bar() [foo()]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Search for references in a hierarchy should find matches in super type.
 * (regression test for bug 31748 [search] search for reference is broken 2.1 M5)
 */
public void testHierarchyScope2() throws CoreException {
	try {
		createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/X.java",
			"package p;\n" +
			"public class X {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"	void bar() {\n" +
			"		foo();\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P1"}, "");
		createFile(
			"/P2/Y.java",
			"import p.X;\n" +
			"public class Y extends X {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"}"
		);
		createFile(
			"/P2/Z.java",
			"public class Z extends Y {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"}"
		);

		ICompilationUnit cu = getCompilationUnit("/P2/Z.java");
		IType type = cu.getType("Z");
		IMethod method = type.getMethod("foo", new String[] {});
		IJavaSearchScope scope = SearchEngine.createHierarchyScope(type);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"p/X.java [in P1] void p.X.bar() [foo()]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Search for references in a hierarchy should find matches in super type.
 * (regression test for bug 35755 Search in hierarchy misses dependent projects )
 */
public void testHierarchyScope3() throws CoreException {
	try {
		createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/X.java",
			"package p;\n" +
			"public class X {\n" +
			"	protected void foo() {\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P1"}, "");
		createFolder("/P2/q");
		createFile(
			"/P2/q/Y.java",
			"package q;\n" +
			"import p.X;\n" +
			"public class Y extends X {\n" +
			"	void bar() {\n" +
			"		foo();\n" +
			"	}\n" +
			"}"
		);

		ICompilationUnit cu = getCompilationUnit("/P1/p/X.java");
		IType type = cu.getType("X");
		IMethod method = type.getMethod("foo", new String[] {});
		IJavaSearchScope scope = SearchEngine.createHierarchyScope(type);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"q/Y.java [in P2] void q.Y.bar() [foo()]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Search for references in a hierarchy should not find inaccurate match if reference is indirect.
 * (regression test for bug 35755 Search in hierarchy misses dependent projects )
 */
public void testHierarchyScope4() throws CoreException {
	try {
		createJavaProject("P0");
		createFolder("/P0/p0");
		createFile(
			"/P0/p0/X.java",
			"package p0;\n" +
			"public class X {\n" +
			"  public static X TheX;\n" +
			"	public void foo() {\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P1", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P0"}, "");
		createFolder("/P1/p1");
		createFile(
			"/P1/p1/T.java",
			"package p1;\n" +
			"import p0.X;\n" +
			"public class T {\n" +
			"	public X zork() {\n" +
			"		return X.TheX;\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P0", "/P1"}, "");
		createFolder("/P2/p2");
		createFile(
			"/P2/p2/Y.java",
			"package p2;\n" +
			"import p0.X;\n" +
			"import p1.T;\n" +
			"public class Y extends X {\n" +
			"	public void bar() {\n" +
			"		new T().zork().foo();\n" +
			"	}\n" +
			"}"
		);
		createJavaProject("P3", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P0", "/P2"}, "");
		createFolder("/P3/p3");
		createFile(
			"/P3/p3/Z.java",
			"package p3;\n" +
			"import p0.X;\n" +
			"import p2.Y;\n" +
			"public class Z extends Y {\n" +
			"	static {\n" +
			"		X.TheX = new Z(); // zork() will actually answer an instance of Z\n" +
			"	}\n" +
			"	public void foo() {\n" +
			"	} // refs should find one in Y.bar()\n" +
			"}"
		);

		ICompilationUnit cu = getCompilationUnit("/P3/p3/Z.java");
		IType type = cu.getType("Z");
		IMethod method = type.getMethod("foo", new String[] {});
		IJavaSearchScope scope = SearchEngine.createHierarchyScope(type);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showAccuracy(true);
		resultCollector.showProject();
		search(
			method,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"p2/Y.java [in P2] void p2.Y.bar() [foo()] EXACT_MATCH",
			resultCollector);
	} finally {
		deleteProjects(new String[] {"P0", "P1", "P2", "P3"});
	}
}
/**
 * Method occurences with 2 unrelated projects that contain the same source.
 * (regression test for bug 33800 search: reporting too many method occurrences)
 */
public void testMethodOccurences() throws CoreException {
	try {
		// setup project P1
		IJavaProject p1 = createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/I.java",
			"package p;\n" +
			"public interface I {\n" +
			"    void method(Object o);\n" +
			"}"
		);
		createFile(
			"/P1/p/C.java",
			"package p;\n" +
			"public class C implements I {\n" +
			"    void method(Object o) {\n" +
			"    }\n" +
			"}"
		);

		// copy to project P2
		p1.getProject().copy(new Path("/P2"), false, null);
		IJavaProject p2 = getJavaProject("P2");

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		IMethod method = getCompilationUnit("/P1/p/I.java").getType("I").getMethod("method", new String[] {"QObject;"});
		search(
			method,
			ALL_OCCURRENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected occurences of method p.I.method(Object)",
			"p/C.java [in P1] void p.C.method(Object) [method]\n" +
			"p/I.java [in P1] void p.I.method(Object) [method]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Package declaration with 2 unrelated projects that contain the same source.
 * (regression test for bug 46276 Search for package declarations incorrectly finds matches in clone project)
 */
public void testPackageDeclaration() throws CoreException {
	try {
		// setup project P1
		IJavaProject p1 = createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/X.java",
			"package p;\n" +
			"public class X {\n" +
			"}"
		);

		// copy to project P2
		p1.getProject().copy(new Path("/P2"), false, null);
		IJavaProject p2 = getJavaProject("P2");

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		IPackageFragment pkg = getPackage("/P1/p");
		search(
			pkg,
			DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected package declarations",
			"p [in P1] p",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Package reference with fragments in 2 different source projects.
 * (regression test for bug 47415 [Search] package references confused with multiple fragments)
 */
public void testPackageReference1() throws CoreException {
	try {
		// setup project P1
		IJavaProject p1 = createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/X.java",
			"package p;\n" +
			"public class X {\n" +
			"}"
		);

		// setup project P2
		IJavaProject p2 = createJavaProject(
			"P2",
			new String[] {""},
			new String[] {"JCL_LIB"},
			new String[] {"/P1"},
			"");
		createFolder("/P2/p");
		createFile(
			"/P2/p/Y.java",
			"package p;\n" +
			"public class Y {\n" +
			"}"
		);

		// create package references
		createFolder("/P2/q");
		createFile(
			"/P2/q/Z.java",
			"package q;\n" +
			"import p.X;\n" +
			"import p.Y;\n" +
			"public class Z {\n" +
			"  X onlyHereForTheImport = null;\n" +
			"  Y alsoOnlyHereForTheImport = null;\n" +
			"  void foo(){\n" +
			"    p.X x = (p.X)null;\n" +
			"    p.Y y = (p.Y)null;\n" +
			"  }\n" +
			"}"
		);

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		IPackageFragment pkg = getPackage("/P1/p");
		search(
			pkg,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected package references",
			"q/Z.java [p]\n" +
			"q/Z.java void q.Z.foo() [p]\n" +
			"q/Z.java void q.Z.foo() [p]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Package reference with fragments in 2 different binary projects.
 * (regression test for bug 47415 [Search] package references confused with multiple fragments)
 */
public void testPackageReference2() throws CoreException, IOException {
	try {
		// setup project JavaSearchMultipleProjects1
		IJavaProject p1 = setUpJavaProject("JavaSearchMultipleProjects1");

		// setup project JavaSearchMultipleProjects2
		IJavaProject p2 = setUpJavaProject("JavaSearchMultipleProjects2");

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		IPackageFragment pkg = getPackage("/JavaSearchMultipleProjects1/lib/p");
		search(
			pkg,
			REFERENCES,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected package references",
			"src/q/Z.java [p]\n" +
			"src/q/Z.java void q.Z.foo() [p]\n" +
			"src/q/Z.java void q.Z.foo() [p]",
			resultCollector);
	} finally {
		deleteProject("JavaSearchMultipleProjects1");
		deleteProject("JavaSearchMultipleProjects2");
	}
}
/**
 * Method reference with 2 working copies in 2 different project.
 * (regression test for bug 57749 Search in working copies doesn't find all matches)
 */
public void testReferenceInWorkingCopies() throws CoreException {
	ICompilationUnit workingCopy1 = null;
	ICompilationUnit workingCopy2 = null;
	try {
		// setup project P1
		IJavaProject p1 = createJavaProject("P1");
		createFolder("/P1/p1");
		createFile(
			"/P1/p1/X.java",
			"package p1;\n" +
			"public class X {\n" +
			"  void foo() {\n" +
			"  }\n" +
			"}"
		);
		createFile(
			"/P1/p1/Test.java",
			"package p1;\n" +
			"public class Test {\n" +
			"}"
		);

		// setup project P2
		IJavaProject p2 = createJavaProject(
			"P2",
			new String[] {""},
			new String[] {"JCL_LIB"},
			new String[] {"/P1"},
			"");
		createFolder("/P2/p2");
		createFile(
			"/P2/p2/Y.java",
			"package p2;\n" +
			"public class Y {\n" +
			"}"
		);
		// need a second potential match to see the problem
		createFile(
			"/P2/p2/Z.java",
			"public class Z {\n" +
			"  void bar(p1.Test test) {\n" +
			"  }\n" +
			"  void foo() {\n" +
			"    bar(null);\n" + // potential match
			"  }\n" +
			"}"
		);

		// create working copies
		WorkingCopyOwner owner = new WorkingCopyOwner() {};
		workingCopy1 = getCompilationUnit("/P1/p1/X.java").getWorkingCopy(owner, null/*no progress monitor*/);
		workingCopy1.getBuffer().setContents(
			"package p1;\n" +
			"public class X {\n" +
			"  void bar(Test test) {\n" +
			"  }\n" +
			"}"
		);
		workingCopy1.makeConsistent(null);
		workingCopy2 = getCompilationUnit("/P2/p2/Y.java").getWorkingCopy(owner, null/*no progress monitor*/);
		workingCopy2.getBuffer().setContents(
			"package p2;\n" +
			"import p1.X;\n" +
			"public class Y {\n" +
			"  void fred() {\n" +
			"    new X().bar(null);\n" +
			"  }\n" +
			"}"
		);
		workingCopy2.makeConsistent(null);

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		IMethod method = workingCopy1.getType("X").getMethod("bar", new String[] {"QTest;"});
		new SearchEngine(owner).search(
			SearchPattern.createPattern(method, REFERENCES),
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			scope,
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected package references",
			"p2/Y.java void p2.Y.fred() [bar(null)]",
			resultCollector);
	} finally {
		if (workingCopy1 != null) workingCopy1.discardWorkingCopy();
		if (workingCopy2 != null) workingCopy1.discardWorkingCopy();
		deleteProject("P1");
		deleteProject("P2");
	}
}
/**
 * Type declaration in external jar file that is shared by 2 projects.
 * (regression test for bug 27485 SearchEngine returns wrong java element when searching in an archive that is included by two distinct java projects.)
 */
public void testTypeDeclarationInJar() throws CoreException {
	try {
		IJavaProject p1 = createJavaProject("P1", new String[] {}, new String[] {"JCL_LIB"}, "");
		IJavaProject p2 = createJavaProject("P2", new String[] {}, new String[] {"JCL_LIB"}, "");

		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p1});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			"Object",
			TYPE,
			DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected result in scope of P1",
			getExternalJCLPathString() + " [in P1] java.lang.Object",
			resultCollector);

		scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p2});
		resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			"Object",
			TYPE,
			DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected result in scope of P2",
			getExternalJCLPathString() + " [in P2] java.lang.Object",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}

/**
 * Bug 151189: [search] Declaration search does not find all matches
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=151189"
 */
public void testBug151189_Workspace() throws CoreException {
	try {
		// setup project P1
		/*IJavaProject p1 = */createJavaProject("P1");
		createFolder("/P1/pack");
		createFile(
			"/P1/pack/Declaration.java",
			"package pack;\n" +
			"public class Declaration implements Interface {\n" +
			"	public void doOperation(int val) {}\n" +
			"}\n"
		);
		createFile(
			"/P1/pack/Interface.java",
			"package pack;\n" +
			"public interface Interface {\n" +
			"	void doOperation(int val);\n" +
			"}\n"
		);

		// setup project P2
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] { "/P1" }, "");
		createFolder("/P2/test");
		createFile(
			"/P2/test/Declaration_bis.java",
			"package test;\n" +
			"import pack.Interface;\n" +
			"public class Declaration_bis implements Interface {\n" +
			"	public void doOperation(int val) {}\n" +
			"}\n"
		);

		// Get method
		IMethod method = getCompilationUnit("/P2/test/Declaration_bis.java").getType("Declaration_bis").getMethod("doOperation", new String[] {"I"});

		// search method declaration in workspace scope
		IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); //JavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected declarations of method test.Declaration_bis.doOperation(int)",
			"test/Declaration_bis.java [in P2] void test.Declaration_bis.doOperation(int) [doOperation]",
			resultCollector);

		// search method declaration in workspace scope with JDT-UI flags
		resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			UI_DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected declarations of method test.Declaration_bis.doOperation(int)",
			"pack/Declaration.java [in P1] void pack.Declaration.doOperation(int) [doOperation]\n" +
			"pack/Interface.java [in P1] void pack.Interface.doOperation(int) [doOperation]\n" +
			"test/Declaration_bis.java [in P2] void test.Declaration_bis.doOperation(int) [doOperation]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
public void testBug151189_Project() throws CoreException {
	try {
		// setup project P1
		createJavaProject("P1");
		createFolder("/P1/pack");
		createFile(
			"/P1/pack/Declaration.java",
			"package pack;\n" +
			"public class Declaration implements Interface {\n" +
			"	public void doOperation(int val) {}\n" +
			"}\n"
		);
		createFile(
			"/P1/pack/Interface.java",
			"package pack;\n" +
			"public interface Interface {\n" +
			"	void doOperation(int val);\n" +
			"}\n"
		);

		// setup project P2
		IJavaProject p2 = createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] { "/P1" }, "");
		createFolder("/P2/test");
		createFile(
			"/P2/test/Declaration_bis.java",
			"package test;\n" +
			"import pack.Interface;\n" +
			"public class Declaration_bis implements Interface {\n" +
			"	public void doOperation(int val) {}\n" +
			"}\n"
		);

		// Get method
		IMethod method = getCompilationUnit("/P2/test/Declaration_bis.java").getType("Declaration_bis").getMethod("doOperation", new String[] {"I"});

		// search method declaration in project scope
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		search(
			method,
			UI_DECLARATIONS,
			scope,
			resultCollector);
		assertSearchResults(
			"Unexpected declarations of method test.Declaration_bis.doOperation(int)",
			"pack/Declaration.java [in P1] void pack.Declaration.doOperation(int) [doOperation]\n" +
			"pack/Interface.java [in P1] void pack.Interface.doOperation(int) [doOperation]\n" +
			"test/Declaration_bis.java [in P2] void test.Declaration_bis.doOperation(int) [doOperation]",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}

/**
 * @bug 163072: [search] method reference reports wrong potential matches
 * @test Ensure that there's no potential match while searching in two projects having 1.4 and 1.5 compliances
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=163072"
 */
public void testBug163072() throws CoreException {
	try {
		// setup project P1
		/*IJavaProject p1 = */createJavaProject("P1"); // standard project using 1.4 compliance
		createFolder("/P1/test");
		createFile(
			"/P1/test/Test.java",
			"package test;\n" +
			"public class Test {\n" +
			"	public Object getType() {\n" +
			"		return null;\n" +
			"	}\n" +
			"	public void foo() {\n" +
			"		if (getType() == null) {\n" +
			"			System.out.println(\"null\");\n" +
			"		}\n" +
			"	}\n" +
			"}\n"
		);

		// setup project P2
		createJavaProject("P2", new String[] {""}, new String[] {"JCL15_LIB"}, new String[] { "/P1" }, "", "1.5");
		createFolder("/P2/pack");
		createFile(
			"/P2/pack/FactoryContainer.java",
			"package pack;\n" +
			"public class FactoryContainer {\n" +
			"	public enum FactoryType { PLUGIN }\n" +
			"	public FactoryType getType() {\n" +
			"		return FactoryType.PLUGIN;\n" +
			"	}\n" +
			"}\n"
		);
		createFile(
			"/P2/pack/Reference.java",
			"package pack;\n" +
			"public class Reference {\n" +
			"	private final FactoryContainer _fc;\n" +
			"	public Reference() {\n" +
			"		_fc = new FactoryContainer();\n" +
			"	}\n" +
			"	boolean foo() {\n" +
			"		return _fc.getType() == FactoryContainer.FactoryType.PLUGIN;\n" +
			"	}\n" +
			"}\n"
		);

		// Get method
		IMethod method = getCompilationUnit("/P1/test/Test.java").getType("Test").getMethod("getType", new String[0]);
		assertTrue("Method 'Test.getType()' should exist!", method.exists());

		// search method declaration in workspace scope
		IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); //JavaSearchScope(new IJavaElement[] {p1, p2});
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		search(method, REFERENCES, scope, resultCollector);
		assertSearchResults(
			"Unexpected references of method Test.getType()",
			"test/Test.java [in P1] void test.Test.foo() [getType()] EXACT_MATCH",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}

/**
 * @bug 167743: [search] Open Type Dialog cannot find types from projects migrated from 3.2.1 workspace
 * @test Ensure that types are found even in default package fragment root
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=167743"
 */
public void testBug167743() throws CoreException {
	try {
		IJavaProject p = createJavaProject("P");
		createFolder("/P/test");
		createFile(
			"/P/test/TestClass.java",
			"package test;\n" +
			"public class Test {\n" +
			"}\n"
		);

		// Search all type names with TypeNameMatchRequestor
		AbstractJavaSearchTests.TypeNameMatchCollector collector = new AbstractJavaSearchTests.TypeNameMatchCollector() {
			public String toString(){
				return toFullyQualifiedNamesString();
			}
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { p });
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { '*' },
			SearchPattern.R_PATTERN_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			collector,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		// Search all type names with TypeNameRequestor
		SearchTests.SearchTypeNameRequestor requestor = new SearchTests.SearchTypeNameRequestor();
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { '*' },
			SearchPattern.R_PATTERN_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			requestor,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		// Should have same types with these 2 searches
		assertEquals("Invalid number of types found!", requestor.size(), collector.size());
		assertEquals("Found types sounds not to be correct", requestor.toString(), collector.toString());
	} finally {
		deleteProject("P");
	}
}

/**
 * @bug 176831: [search] No search results due to malformed search scope
 * @test Verify that type are found in rt.jar even if it's added as a library on the classpath
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=176831"
 */
public void testBug176831() throws CoreException {
	try {
		// Create projects and files
		final IJavaProject p1 = createJavaProject("P1", new String[] {"src"}, null, new String[] {"/P2"}, "bin");
		final IJavaProject p2 = createJavaProject("P2", new String[] {"src"}, new String[] { getExternalJCLPathString() }, "bin");

		// Create scope and search
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { p1, p2 }, IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.REFERENCED_PROJECTS);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		new SearchEngine().search(
			SearchPattern.createPattern("toString", IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH),
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			scope,
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected references to /P1/p/A.java",
			""+ getExternalJCLPathString() + " [in P2] java.lang.String java.lang.Object.toString() EXACT_MATCH",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
	}
}
public void testBug176831b() throws CoreException {
	try {
		// Create projects and files
		final IJavaProject p1 = createJavaProject("P1", new String[] {"src"}, null, new String[] {"/P2"}, "bin");
		final IJavaProject p2 = createJavaProject("P2", new String[] {"src"}, null, new String[] {"/P3"}, "bin");
		final IJavaProject p3 = createJavaProject("P3", new String[] {"src"}, new String[] { getExternalJCLPathString() }, "bin");

		// Create scope and search
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { p1, p2, p3 }, IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.REFERENCED_PROJECTS);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		new SearchEngine().search(
			SearchPattern.createPattern("toString", IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH),
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			scope,
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected references to /P1/p/A.java",
			""+ getExternalJCLPathString() + " [in P3] java.lang.String java.lang.Object.toString() EXACT_MATCH",
			resultCollector);
	} finally {
		deleteProject("P1");
		deleteProject("P2");
		deleteProject("P3");
	}
}

/**
 * @bug 195228: [search] Invalid path in open type dialog
 * @test Verify that correct types are found even with project and source folders in the classpath
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=195228"
 */
public void testBug195228() throws CoreException {
	try {
		// Create projects and files
		final IJavaProject project = createJavaProject("P1", new String[] {"src"}, "bin");
		createFolder("/P1/src/pack1/pack2");
		createFile(
			"/P1/src/pack1/pack2/X.java",
			"package pack1.pack2;\n" +
			"public class X {}"
		);
		createFile(
			"/P1/src/pack1/Y.java",
			"package pack1;\n" +
			"public class Y {}"
		);
		createFile(
			"/P1/test.properties",
			"bug=195228"
		);
		// Create additional projects to force the rehash of the workspace scope while creating it
		createJavaProject("P2", new String[] {"src"}, "bin");
		createJavaProject("P3", new String[] {"src"}, "bin");
		IJavaSearchScope scope = SearchEngine.createWorkspaceScope();

		// Store all types found in project
		TypeNameMatchCollector requestor = new TypeNameMatchCollector();
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			null,
			SearchPattern.R_PREFIX_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			requestor,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		String allTypes = requestor.toString();

		// Add project folder to classpath with inclusion and exclusion patterns
		getWorkspace().run(new IWorkspaceRunnable() {
			public void run(IProgressMonitor monitor) throws CoreException {
				IClasspathEntry[] entries = project.getRawClasspath();
				int length = entries.length;
				System.arraycopy(entries, 0, entries = new IClasspathEntry[length+1], 0, length);
				entries[length] = JavaCore.newSourceEntry(new Path("/P1"), new IPath[] { new Path("test.properties") }, new IPath[] { new Path("src/") }, null);
				project.setRawClasspath(entries, null);
			}
		}, null);

		// Search for all types and verify that same are found
		requestor = new TypeNameMatchCollector();
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			null,
			SearchPattern.R_PREFIX_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			requestor,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		assertEquals("Should found same types!", allTypes, requestor.toString());
	} finally {
		deleteProject("P1");
		deleteProject("P2");
		deleteProject("P3");
	}
}

/**
 * @bug 199392: [search] Type Dialog Error 'Items filtering ... Reason: Class file name must end with .class'
 * @test Ensure that types are found even in project which name ends either with ".jar" or ".zip"
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=199392"
 */
public void testBug199392_Jar() throws CoreException {
	try {
		IJavaProject project = createJavaProject("Test.jar");
		createFolder("/Test.jar/test");
		createFile(
			"/Test.jar/test/MyClass.java",
			"package test;\n" +
			"public class MyClass {\n" +
			"}\n"
		);

		// Search all type names with TypeNameMatchRequestor
		AbstractJavaSearchTests.TypeNameMatchCollector collector = new AbstractJavaSearchTests.TypeNameMatchCollector() {
			public String toString(){
				return toFullyQualifiedNamesString();
			}
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project });
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { 'M', 'y' },
			SearchPattern.R_CAMELCASE_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			collector,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		assertEquals("Found types sounds not to be correct",
			"test.MyClass",
			collector.toString()
		);
	} finally {
		deleteProject("Test.jar");
	}
}
public void testBug199392_Jar_SamePartCount() throws CoreException {
	try {
		IJavaProject project = createJavaProject("Test.jar");
		createFolder("/Test.jar/test");
		createFile(
			"/Test.jar/test/MyClass.java",
			"package test;\n" +
			"public class MyClass {\n" +
			"}\n"
		);

		// Search all type names with TypeNameMatchRequestor
		AbstractJavaSearchTests.TypeNameMatchCollector collector = new AbstractJavaSearchTests.TypeNameMatchCollector() {
			public String toString(){
				return toFullyQualifiedNamesString();
			}
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project });
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { 'M', 'y' },
			SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			collector,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		assertEquals("Found types sounds not to be correct",
			"",
			collector.toString()
		);
	} finally {
		deleteProject("Test.jar");
	}
}
public void testBug199392_Zip() throws CoreException {
	try {
		IJavaProject project = createJavaProject("Test.zip");
		createFolder("/Test.zip/test");
		createFile(
			"/Test.zip/test/MyClass.java",
			"package test;\n" +
			"public class MyClass {\n" +
			"}\n"
		);

		// Search all type names with TypeNameMatchRequestor
		AbstractJavaSearchTests.TypeNameMatchCollector collector = new AbstractJavaSearchTests.TypeNameMatchCollector() {
			public String toString(){
				return toFullyQualifiedNamesString();
			}
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project });
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { 'M', 'y' },
			SearchPattern.R_CAMELCASE_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			collector,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		assertEquals("Found types sounds not to be correct",
			"test.MyClass",
			collector.toString()
		);
	} finally {
		deleteProject("Test.zip");
	}
}
public void testBug199392_Zip_SamePartCount() throws CoreException {
	try {
		IJavaProject project = createJavaProject("Test.zip");
		createFolder("/Test.zip/test");
		createFile(
			"/Test.zip/test/MyClass.java",
			"package test;\n" +
			"public class MyClass {\n" +
			"}\n"
		);

		// Search all type names with TypeNameMatchRequestor
		AbstractJavaSearchTests.TypeNameMatchCollector collector = new AbstractJavaSearchTests.TypeNameMatchCollector() {
			public String toString(){
				return toFullyQualifiedNamesString();
			}
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { project });
		new SearchEngine().searchAllTypeNames(
			null,
			SearchPattern.R_EXACT_MATCH,
			new char[] { 'M', 'y' },
			SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH,
			IJavaSearchConstants.TYPE,
			scope,
			collector,
			IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
			null);
		assertEquals("Found types sounds not to be correct",
			"",
			collector.toString()
		);
	} finally {
		deleteProject("Test.zip");
	}
}

/**
 * @bug 210689: [search] Import references not found on working copies not written on disk
 * @test Ensure that import references are found when searching on working copies not written on disk
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=210689"
 */
public void testBug210689() throws CoreException {
	try {
		// setup project P0
		createJavaProject("P0");
		createFolder("/P0/p");
		createFile(
			"/P0/p/A.java",
			"package p;\n" +
			"public class A {}\n"
		);

		// setup project P1
		createJavaProject("P1");
		createFolder("/P1/p");
		createFile(
			"/P1/p/A.java",
			"package p;\n" +
			"public class A {}\n"
		);

		// setup project P2
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] { "/P1" }, "");
		createFolder("/P2/p");
		createFile(
			"/P2/p/B.java",
			"package p;\n" +
			"public class B {}\n"
		);
		createFile(
			"/P2/p/Ref.java",
			"package p;\n" +
			"public class Ref {\n" +
			"	A a;\n" +
			"	B b;\n" +
			"}\n"
		);

		// Create OR pattern
		IType typeA0 = getCompilationUnit("/P0/p/A.java").getType("A");
		IType typeA1 = getCompilationUnit("/P1/p/A.java").getType("A");
		SearchPattern rightPattern = SearchPattern.createPattern(typeA0, REFERENCES);
		SearchPattern leftPattern = SearchPattern.createPattern(typeA1, REFERENCES);
		SearchPattern pattern = SearchPattern.createOrPattern(leftPattern, rightPattern);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		new SearchEngine().search(
			pattern,
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			SearchEngine.createWorkspaceScope(),
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected references to /P1/p/A.java",
			"p/Ref.java [in P2] p.Ref.a [A] EXACT_MATCH",
			resultCollector);
	} finally {
		deleteProject("P0");
		deleteProject("P1");
		deleteProject("P2");
	}
}

/**
 * @bug 229128: JDT Search finding matches in working copies that are not part of scope
 * @test Ensure that an annotation reference is not found in a working copy if outside the scope
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=229128"
 */
public void testBug229128() throws CoreException {
	ICompilationUnit[] copies = new ICompilationUnit[2];
	try {
		// setup project P1
		createJavaProject("P1", new String[] {""}, new String[] {"JCL15_LIB"}, "", "1.5");
		createFolder("/P1/p");
		createFile(
			"/P1/p/MyAnnot.java",
			"package p;\n" +
			"public @interface MyAnnot {\n" +
			"}\n"
		);
		copies[0] = getWorkingCopy(
			"/P1/p/X.java",
			"package p;\n" +
			"@MyAnnot\n" +
			"public class X {\n" +
			"}\n",
			null/*default working copy owner*/
		);

		// setup project P2
		IJavaProject p2 = createJavaProject("P2", new String[] {""}, new String[] {"JCL15_LIB"}, new String[] { "/P1" }, "", "1.5");
		createFolder("/P2/q");
		copies[1] = getWorkingCopy(
			"/P2/q/Y.java",
			"package q;\n" +
			"@p.MyAnnot\n" +
			"public class Y {\n" +
			"}\n",
			null/*default working copy owner*/
		);

		// Get annotation type
		IType type = getCompilationUnit("/P1/p/MyAnnot.java").getType("MyAnnot");

		// search annotation type reference in P2 scope
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p2}, false/*don't include referenced projects*/);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		search(type, ANNOTATION_TYPE_REFERENCE, scope, resultCollector);
		assertSearchResults(
			"Unexpected references of annotation type MyAnnot",
			"q/Y.java [in P2] q.Y [p.MyAnnot] EXACT_MATCH",
			resultCollector);
	} finally {
		discardWorkingCopies(copies);
		deleteProject("P1");
		deleteProject("P2");
	}
}

/**
 * @bug 229951: StackOverflowError during JavaSearchScope.add for large workspace
 * @test Ensure that no StackOverFlowError occurs when searching in a project referencing a cycle
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=229951"
 */
public void testBug229951a() throws Exception {
	try {
		createJavaProject("P1");
		createFile("/P1/test.jar", "");
		editFile(
			"/P1/.classpath",
			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
			"<classpath>\n" +
			"	<classpathentry kind=\"lib\" path=\"test.jar\"/>\n" +
			"	<classpathentry exported=\"true\" kind=\"src\" path=\"/P2\"/>\n" +
			"	<classpathentry kind=\"output\" path=\"bin\"/>\n" +
			"</classpath>"
		);
		createJavaProject("P2");
		createFile("/P2/test.jar", "");
		editFile(
			"/P2/.classpath",
			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
			"<classpath>\n" +
			"	<classpathentry kind=\"lib\" path=\"test.jar\"/>\n" +
			"	<classpathentry exported=\"true\" kind=\"src\" path=\"/P1\"/>\n" +
			"	<classpathentry kind=\"output\" path=\"bin\"/>\n" +
			"</classpath>"
		);
		createJavaProject("P3", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P2"}, "");
		createFile(
			"/P3/X229951.java",
			"public class X229951 {\n" +
			"}"
		);
		IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		search("X229951", TYPE, DECLARATIONS, scope, resultCollector);
		assertSearchResults(
			"Unexpected references of annotation type MyAnnot",
			"X229951.java X229951 [X229951]",
			resultCollector);
	} finally {
		deleteProjects(new String[] {"P1", "P2", "P3"});
	}
}

/**
 * @bug 229951: StackOverflowError during JavaSearchScope.add for large workspace
 * @test Ensure that no StackOverFlowError occurs when creating a search scope on a project referencing a cycle
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=229951"
 */
public void testBug229951b() throws Exception {
	try {
		createJavaProject("P1");
		createFile("/P1/test.jar", "");
		editFile(
			"/P1/.classpath",
			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
			"<classpath>\n" +
			"	<classpathentry kind=\"lib\" path=\"test.jar\"/>\n" +
			"	<classpathentry exported=\"true\" kind=\"src\" path=\"/P2\"/>\n" +
			"	<classpathentry kind=\"output\" path=\"bin\"/>\n" +
			"</classpath>"
		);
		createJavaProject("P2");
		createFile("/P2/test.jar", "");
		editFile(
			"/P2/.classpath",
			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
			"<classpath>\n" +
			"	<classpathentry kind=\"lib\" path=\"test.jar\"/>\n" +
			"	<classpathentry exported=\"true\" kind=\"src\" path=\"/P1\"/>\n" +
			"	<classpathentry kind=\"output\" path=\"bin\"/>\n" +
			"</classpath>"
		);
		IJavaProject p3 = createJavaProject("P3", new String[] {""}, new String[] {"JCL_LIB"}, new String[] {"/P2"}, "");
		createFile(
			"/P3/X229951.java",
			"public class X229951 {\n" +
			"}"
		);
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaElement[] {p3});
		assertScopeEquals(
			"JavaSearchScope on [\n" +
			"	/P3\n" +
			"	" + getExternalJCLPathString() + "\n" +
			"]",
			scope);
	} finally {
		deleteProjects(new String[] {"P1", "P2", "P3"});
	}
}

/**
 * @bug 250454: [search] Cannot find method references between projects
 * @test Ensure that search does not find illegal references with given projects setup
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=250454"
 */
public void testBug250454() throws CoreException {
	try {
		// setup project P0
		createJavaProject("P0");
		createFolder("/P0/p");
		createFile(
			"/P0/p/Shape.java",
			"package p;\n" +
			"public interface Shape {\n" + 
			"	public void f();\n" + 
			"}\n"
		);

		// setup project P1
		createJavaProject("P1", new String[] {""}, new String[] {"JCL_LIB"}, new String[] { "/P0" }, "");
		createFolder("/P1/p");
		createFile(
			"/P1/p/Square.java",
			"package p;\n" +
			"public class Square implements Shape {\n" + 
			"	public void f() {}\n" + 
			"}\n"
		);

		// setup project P2
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB"}, new String[] { "/P0" }, "");
		createFolder("/P2/p");
		createFile(
			"/P2/p/ShapeUser.java",
			"package p;\n" +
			"public class ShapeUser {\n" + 
			"	public void useShape(Shape p_shape) {\n" + 
			"		p_shape.f();\n" + 
			"	}\n"
		);

		// Perform search
		IType type = getCompilationUnit("/P1/p/Square.java").getType("Square");
		IMethod method = type.getMethod("f", new String[0]);
		SearchPattern pattern = SearchPattern.createPattern(method, REFERENCES);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		resultCollector.showFlavors = PatternLocator.SUPER_INVOCATION_FLAVOR;
		new SearchEngine().search(
			pattern,
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			SearchEngine.createWorkspaceScope(),
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected references to "+method,
			"p/ShapeUser.java [in P2] void p.ShapeUser.useShape(Shape) [f()] EXACT_MATCH SUPER INVOCATION",
			resultCollector);
	} finally {
		deleteProject("P0");
		deleteProject("P1");
		deleteProject("P2");
	}
}
public void testBug250454_jars() throws CoreException, IOException {
	String jarPath = getExternalPath()+"b250454.jar";
	try {
		// setup jar
		String[] pathsAndContents= new String[] {
			"p/Shape.java",
			"package p;\n" +
			"public interface Shape {\n" + 
			"	public void f();\n" + 
			"}\n"
		};
		createJar(pathsAndContents, jarPath);

		// setup project P1
		createJavaProject("P1", new String[] {""}, new String[] {"JCL_LIB", jarPath}, "");
		createFolder("/P1/p");
		createFile(
			"/P1/p/Square.java",
			"package p;\n" +
			"public class Square implements Shape {\n" + 
			"	public void f() {}\n" + 
			"}\n"
		);

		// setup project P2
		createJavaProject("P2", new String[] {""}, new String[] {"JCL_LIB", jarPath}, "");
		createFolder("/P2/p");
		createFile(
			"/P2/p/ShapeUser.java",
			"package p;\n" +
			"public class ShapeUser {\n" + 
			"	public void useShape(Shape p_shape) {\n" + 
			"		p_shape.f();\n" + 
			"	}\n"
		);

		// Perform search
		IType type = getCompilationUnit("/P1/p/Square.java").getType("Square");
		IMethod method = type.getMethod("f", new String[0]);
		SearchPattern pattern = SearchPattern.createPattern(method, REFERENCES);
		JavaSearchResultCollector resultCollector = new JavaSearchResultCollector();
		resultCollector.showProject();
		resultCollector.showAccuracy(true);
		resultCollector.showFlavors = PatternLocator.SUPER_INVOCATION_FLAVOR;
		new SearchEngine().search(
			pattern,
			new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()},
			SearchEngine.createWorkspaceScope(),
			resultCollector,
			null
		);
		assertSearchResults(
			"Unexpected references to "+method,
			"p/ShapeUser.java [in P2] void p.ShapeUser.useShape(Shape) [f()] EXACT_MATCH SUPER INVOCATION",
			resultCollector);
	} finally {
		deleteExternalFile(jarPath);
		deleteProject("P1");
		deleteProject("P2");
	}
}
}
