Bug 543776 - provide the project as parameter instead of resolving it.

Instead of getting the project with the name from the .project file from
the workspace root, provide the project as parameter directly to the
method getAllBuildConfigReferences of class ProjectDescription.

Add test ProjectDynamicReferencesTest for dynamicReference feature of
builder extension point.
Add regression test ProjectDynamicReferencesTest#testBug543776 for bug.

Signed-off-by: Reto Weiss <reto.weiss@axonivy.com>
Change-Id: Id80e1ceeaeebe21bc549dd909f19e512631ce7a9
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
index c4e20cc..2a6dc32 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
@@ -470,7 +470,7 @@
 		//if the project is currently in the middle of being created, the description might not be available yet
 		if (description == null)
 			checkAccessible(NULL_FLAG);
-		return description.getAllReferences(true);
+		return description.getAllReferences(this, true);
 	}
 
 	@Override
@@ -499,7 +499,7 @@
 			ProjectDescription description = project.internalGetDescription();
 			if (description == null)
 				continue;
-			IProject[] references = description.getAllReferences(false);
+			IProject[] references = description.getAllReferences(project, false);
 			for (IProject reference : references)
 				if (reference.equals(this)) {
 					result.add(project);
@@ -792,7 +792,7 @@
 	 */
 	public IBuildConfiguration[] internalGetReferencedBuildConfigs(String configName, boolean includeMissing) {
 		ProjectDescription description = internalGetDescription();
-		IBuildConfiguration[] refs = description.getAllBuildConfigReferences(configName, false);
+		IBuildConfiguration[] refs = description.getAllBuildConfigReferences(this, configName, false);
 		Collection<IBuildConfiguration> configs = new LinkedHashSet<>(refs.length);
 		for (IBuildConfiguration ref : refs) {
 			try {
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java
index cea29da..bd81623 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ProjectDescription.java
@@ -205,9 +205,9 @@
 	 * Returns the union of the description's static and dynamic project references,
 	 * with duplicates omitted. The calculation is optimized by caching the result
 	 * Call the configuration based implementation.
-	 * @see #getAllBuildConfigReferences(String, boolean)
+	 * @see #getAllBuildConfigReferences(IProject, String, boolean)
 	 */
-	public IProject[] getAllReferences(boolean makeCopy) {
+	public IProject[] getAllReferences(IProject project, boolean makeCopy) {
 		int dirtyCount;
 		IProject[] projRefs;
 
@@ -221,12 +221,12 @@
 		while (projRefs == null) {
 			IBuildConfiguration[] refs;
 			if (hasBuildConfig(activeConfiguration))
-				refs = getAllBuildConfigReferences(activeConfiguration, false);
+				refs = getAllBuildConfigReferences(project, activeConfiguration, false);
 			else if (configNames.length > 0)
-				refs = getAllBuildConfigReferences(configNames[0], false);
+				refs = getAllBuildConfigReferences(project, configNames[0], false);
 			else
 				// No build configuration => fall-back to default
-				refs = getAllBuildConfigReferences(IBuildConfiguration.DEFAULT_CONFIG_NAME, false);
+				refs = getAllBuildConfigReferences(project, IBuildConfiguration.DEFAULT_CONFIG_NAME, false);
 			Collection<IProject> l = getProjectsFromBuildConfigRefs(refs);
 
 			synchronized (cachedRefsMutex) {
@@ -254,14 +254,13 @@
 	 * be resolved using {@link BuildConfiguration#getBuildConfig()} before use.
 	 * Returns an empty array if the given configName does not exist in the description.
 	 */
-	public IBuildConfiguration[] getAllBuildConfigReferences(String configName, boolean makeCopy) {
+	public IBuildConfiguration[] getAllBuildConfigReferences(IProject project, String configName, boolean makeCopy) {
 		if (!hasBuildConfig(configName))
 			return EMPTY_BUILD_CONFIG_REFERENCE_ARRAY;
 		IBuildConfiguration[] refs = cachedConfigRefs.get(configName);
 		if (refs == null) {
 			Set<IBuildConfiguration> references = new LinkedHashSet<>();
 			IBuildConfiguration[] dynamicBuildConfigs = dynamicConfigRefs.containsKey(configName) ? dynamicConfigRefs.get(configName) : EMPTY_BUILD_CONFIG_REFERENCE_ARRAY;
-			IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(getName());
 			Collection<BuildConfiguration> dynamic;
 			try {
 				IBuildConfiguration buildConfig = project.getBuildConfig(configName);
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
index c76cb3a..4f31a1b 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java
@@ -676,7 +676,7 @@
 			if (desc == null)
 				continue;
 			//obtain both static and dynamic project references
-			IProject[] refs = desc.getAllReferences(false);
+			IProject[] refs = desc.getAllReferences(project, false);
 			allAccessibleProjects.add(project);
 			for (IProject ref : refs) {
 				// ignore self references and references to projects that are not accessible
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/ProjectDynamicReferencesTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/ProjectDynamicReferencesTest.java
index 12bfa4a..dfe915d 100644
--- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/ProjectDynamicReferencesTest.java
+++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/ProjectDynamicReferencesTest.java
@@ -17,6 +17,7 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.eclipse.core.resources.*;
+import org.eclipse.core.resources.IWorkspace.ProjectOrder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.tests.resources.ResourceTest;
@@ -30,6 +31,7 @@
 	private static final String PROJECT_0_NAME = "ProjectDynamicReferencesTest_p0";
 
 	private static final IProject[] EMPTY_PROJECTS = new IProject[0];
+	private static final IBuildConfiguration[] EMPTY_BUILD_CONFIGURATIONS = new IBuildConfiguration[0];
 
 	private IProject project0;
 	private IProject project1;
@@ -71,7 +73,7 @@
 		project2.delete(true, null);
 	}
 
-	public void testReferences() throws CoreException {
+	public void testReferencedProjects() throws CoreException {
 		assertEquals("Project0 must not have referenced projects", EMPTY_PROJECTS, project0.getReferencedProjects());
 		assertEquals("Project1 must not have referenced projects", EMPTY_PROJECTS, project1.getReferencedProjects());
 		assertEquals("Project2 must not have referenced projects", EMPTY_PROJECTS, project2.getReferencedProjects());
@@ -115,8 +117,112 @@
 		assertEquals("Project2 must not have referenced projects", EMPTY_PROJECTS, project2.getReferencedProjects());
 	}
 
-	// Temporarily disabled, see bug 543776 comment 7
-	public void XXXtestBug543776() throws CoreException {
+	public void testReferencedBuildConfigs() throws CoreException {
+		assertEquals("Project0 must not have referenced projects", EMPTY_BUILD_CONFIGURATIONS,
+				project0.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+		assertEquals("Project1 must not have referenced projects", EMPTY_BUILD_CONFIGURATIONS,
+				project1.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+		assertEquals("Project2 must not have referenced projects", EMPTY_BUILD_CONFIGURATIONS,
+				project2.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+	
+		DynamicReferenceProvider.addReference(project0, project1);
+		DynamicReferenceProvider.addReference(project1, project2);
+		DynamicReferenceProvider.addReference(project0, project2);
+		clearCache();
+	
+		IBuildConfiguration buildConfigProject1 = project1.getBuildConfig(IBuildConfiguration.DEFAULT_CONFIG_NAME);
+		IBuildConfiguration buildConfigProject2 = project2.getBuildConfig(IBuildConfiguration.DEFAULT_CONFIG_NAME);
+		assertEquals("Build configuration of Project0 must reference build configuration of project1 and project2",
+				new IBuildConfiguration[] { buildConfigProject1, buildConfigProject2 },
+				project0.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+		assertEquals("Build configuration of Project1 must reference build configuration of Project2",
+				new IBuildConfiguration[] { buildConfigProject2 },
+				project1.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+		assertEquals("Project2 must not have referenced projects", EMPTY_BUILD_CONFIGURATIONS,
+				project2.getReferencedBuildConfigs(IBuildConfiguration.DEFAULT_CONFIG_NAME, false));
+	}
+
+	public void testReferencingProjects() throws CoreException {
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must not have referencing projects", EMPTY_PROJECTS, project1.getReferencingProjects());
+		assertEquals("Project2 must not have referencing projects", EMPTY_PROJECTS, project2.getReferencingProjects());
+
+		DynamicReferenceProvider.addReference(project0, project1);
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must not have referencing projects", EMPTY_PROJECTS, project1.getReferencingProjects());
+		assertEquals("Project2 must not have referencing projects", EMPTY_PROJECTS, project2.getReferencingProjects());
+
+		clearCache();
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must be referenced by Project0", new IProject[] { project0 },
+				project1.getReferencingProjects());
+		assertEquals("Project2 must not have referencing projects", EMPTY_PROJECTS, project2.getReferencingProjects());
+
+		DynamicReferenceProvider.addReference(project1, project2);
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must must be referenced by Project0", new IProject[] { project0 },
+				project1.getReferencingProjects());
+		assertEquals("Project2 must not have referencing projects", EMPTY_PROJECTS, project2.getReferencingProjects());
+
+		clearCache();
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must be referenced by Project0", new IProject[] { project0 },
+				project1.getReferencingProjects());
+		assertEquals("Project2 must be referenced by Project1", new IProject[] { project1 },
+				project2.getReferencingProjects());
+
+		DynamicReferenceProvider.addReference(project0, project2);
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must be referenced by Project0", new IProject[] { project0 },
+				project1.getReferencingProjects());
+		assertEquals("Project2 must be referenced by Project1", new IProject[] { project1 },
+				project2.getReferencingProjects());
+
+		clearCache();
+
+		assertEquals("Project0 must not have referencing projects", EMPTY_PROJECTS, project0.getReferencingProjects());
+		assertEquals("Project1 must be referenced by Project0", new IProject[] { project0 },
+				project1.getReferencingProjects());
+		assertEquals("Project2 must be referenced by Project0 and Project1", new IProject[] { project0, project1 },
+				project2.getReferencingProjects());
+	}
+
+	public void testComputeProjectOrder() throws CoreException {
+		IProject[] allProjects = new IProject[] { project0, project1, project2 };
+
+		ProjectOrder projectOrder = getWorkspace().computeProjectOrder(allProjects);
+
+		assertEquals("Build order not defined, must return projects in default order", allProjects, projectOrder.projects);
+		assertFalse("No cycles", projectOrder.hasCycles);
+
+		DynamicReferenceProvider.addReference(project0, project1);
+		DynamicReferenceProvider.addReference(project1, project2);
+		clearCache();
+
+		projectOrder = getWorkspace().computeProjectOrder(allProjects);
+
+		assertEquals("Build order must be Project2, Project1, Project0",
+				new IProject[] { project2, project1, project0 }, projectOrder.projects);
+		assertFalse("No cycles", projectOrder.hasCycles);
+
+		DynamicReferenceProvider.clear();
+		DynamicReferenceProvider.addReference(project1, project0);
+		DynamicReferenceProvider.addReference(project0, project2);
+		clearCache();
+
+		projectOrder = getWorkspace().computeProjectOrder(allProjects);
+
+		assertEquals("Build order must be Project2, Project0, Project1",
+				new IProject[] { project2, project0, project1 }, projectOrder.projects);
+		assertFalse("No cycles", projectOrder.hasCycles);
+	}
+
+	public void testBug543776() throws CoreException {
 		IFile projectFile = project0.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
 		String projectDescription = readStringInFileSystem(projectFile);
 		projectDescription = projectDescription.replace(PROJECT_0_NAME, "anotherName");