Bug 412809: Add support for the include task

The org.eclipse.ant.ui-implementation (and the underlying
ant-implementation) is able to handle import-tasks (AntImportNode), but
not include-tasks. This patch adds missing node-type (AntIncludeNode)
and "registers" the new node-type at the node-selection-functionality
(AntModel). Furthermore the new node type needs to handle
target-prefixes correctly on included files (according to the
documentation at https://ant.apache.org/manual/Tasks/include.html). This
functionality is also part of this proposed patch and should allow to
use "multi-hierarchical" includes with/without aliases (i.e. "includes
inside includes" with/without using the "as"-property).

Change-Id: I3320c0073c37cdd590d805f2e42f6378fc771100
Signed-off-by: Alexander Blaas <olaf.dev17@gmail.com>
diff --git a/ant/org.eclipse.ant.tests.ui/Ant Tests/org/eclipse/ant/tests/ui/AntUtilTests.java b/ant/org.eclipse.ant.tests.ui/Ant Tests/org/eclipse/ant/tests/ui/AntUtilTests.java
index 6b2ea6b..c8a1e6a 100644
--- a/ant/org.eclipse.ant.tests.ui/Ant Tests/org/eclipse/ant/tests/ui/AntUtilTests.java
+++ b/ant/org.eclipse.ant.tests.ui/Ant Tests/org/eclipse/ant/tests/ui/AntUtilTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2013 IBM Corporation and others.
+ * Copyright (c) 2004, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,24 +7,30 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Alexander Blaas (arctis Softwaretechnologie GmbH) - bug 412809
  *******************************************************************************/
 package org.eclipse.ant.tests.ui;
 
 import java.io.File;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.ant.internal.ui.AntUtil;
+import org.eclipse.ant.internal.ui.model.AntProjectNode;
 import org.eclipse.ant.internal.ui.model.AntTargetNode;
+import org.eclipse.ant.internal.ui.model.IAntElement;
+import org.eclipse.ant.internal.ui.model.IAntModel;
 import org.eclipse.ant.launching.IAntLaunchConstants;
 import org.eclipse.ant.tests.ui.testplugin.AbstractAntUITest;
 import org.eclipse.core.externaltools.internal.IExternalToolConstants;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.junit.Assert;
 
 public class AntUtilTests extends AbstractAntUITest {
 
@@ -95,6 +101,145 @@
 		assertContains("import-default", targets); //$NON-NLS-1$
 	}
 
+	// for bugfix of bug 412809: Testing a simple "include-hierarchy" (only two levels setting the "as" property)
+	public void testGetIncludeTargetsSimpleHierarchyAlias() {
+		// The file itself contains one target. The included file contains the other one.
+		String buildFileName = "bug412809/simple/buildFileAlias"; //$NON-NLS-1$
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "commonPrefixed.deploy" }; //$NON-NLS-1$ //$NON-NLS-2$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Testing a simple "include-hierarchy" (only two levels without the "as" property)
+	public void testGetIncludeTargetsSimpleHierarchyNoAliases() {
+		// The file itself contains one target. The included file contains the other one.
+		String buildFileName = "bug412809/simple/buildFileNoAlias"; //$NON-NLS-1$
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "common.deploy" }; //$NON-NLS-1$ //$NON-NLS-2$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Testing a complex "include-hierarchy" (three levels, only non-aliases used)
+	public void testGetIncludeTargetsComplexHierarchyNoAlias() {
+		// The file itself contains one target. The included file contains the other one.
+		String buildFileName = "bug412809/complex/noAlias/buildFileHierarchical"; //$NON-NLS-1$
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "commonLv1.deploy", "commonLv1.commonLv2.deploySuper", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				"commonLv1.commonLv2.commonLv3.deployLv3", "commonLv1.commonLv2.commonLv3.commonLv4.deployLv4" }; //$NON-NLS-1$ //$NON-NLS-2$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Testing a complex "include-hierarchy" (three levels, only aliases used)
+	public void testGetIncludeTargetsComplexHierarchyAlias() {
+		// The file itself contains one target. The included file contains the other one.
+		String buildFileName = "bug412809/complex/alias/buildFileHierarchical"; //$NON-NLS-1$
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "commonLv1Prefix.deploy", "commonLv1Prefix.commonLv2Prefix.deploySuper", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				"commonLv1Prefix.commonLv2Prefix.commonLv3Prefix.deployLv3", //$NON-NLS-1$
+				"commonLv1Prefix.commonLv2Prefix.commonLv3Prefix.commonLv4Prefix.deployLv4" }; //$NON-NLS-1$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Testing a complex "include-hierarchy" (three levels, aliases and non-aliases used)
+	public void testGetIncludeTargetsComplexHierarchyMisc() {
+		// The file itself contains one target. The included file contains the other one.
+		String buildFileName = "bug412809/complex/misc/buildFileHierarchical"; //$NON-NLS-1$
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "commonLv1.deploy", "commonLv1.commonLv2.deploySuper", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				"commonLv1.commonLv2.commonLv3Prefix.deployLv3", "commonLv1.commonLv2.commonLv3Prefix.commonLv4Prefix.deployLv4" }; //$NON-NLS-1$ //$NON-NLS-2$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Assure explicitly that the provided patch works on external as well as non-external build-files
+	public void testGetIncludeTargetsExternalFiles() {
+		// First assure that external and non-external files are included
+		String buildFileName = "bug412809/complex/misc/buildFileHierarchical"; //$NON-NLS-1$
+		File buildFile = getBuildFile(buildFileName + ".xml"); //$NON-NLS-1$
+		// tasks and position info but no lexical info
+		IAntModel model = AntUtil.getAntModel(buildFile.getAbsolutePath(), false, true, true);
+		AntProjectNode project = model.getProjectNode();
+
+		// 9 childnodes are contained
+		long childNodesExpected = 9;
+		boolean atLeastOneExternal = false;
+		List<IAntElement> childNodes = project.getChildNodes();
+
+		Assert.assertNotNull(childNodes);
+
+		int actualSize = childNodes.size();
+		Assert.assertEquals("Expecting " + childNodesExpected + " childnodes, but have: " + actualSize, childNodesExpected, actualSize); //$NON-NLS-1$ //$NON-NLS-2$
+
+		for (IAntElement element : childNodes) {
+			// "External" seems to be true if the element was defined within an "importNode" => check the import nodes
+			IAntElement importNode = element.getImportNode();
+
+			if (importNode != null) {
+				Assert.assertTrue(element.isExternal());
+				atLeastOneExternal = true;
+			} else {
+				Assert.assertFalse(element.isExternal());
+			}
+		}
+		// At least on external include-file was found
+		Assert.assertTrue(atLeastOneExternal);
+		// Then just execute the rest of the previous test
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+		String[] expectedTargets = { "deploy", "commonLv1.deploy", "commonLv1.commonLv2.deploySuper", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				"commonLv1.commonLv2.commonLv3Prefix.deployLv3", "commonLv1.commonLv2.commonLv3Prefix.commonLv4Prefix.deployLv4" }; //$NON-NLS-1$ //$NON-NLS-2$
+		assertTargets(targets, expectedTargets);
+	}
+
+	// for bugfix of bug 412809: Testing the performance by including the huge build file from "/testbuildfiles/performance/build.xml"
+	public void testGetIncludeTargetsPerformance() {
+		/*
+		 * More or less the same files (noAlias-files because the parsing to search the project-name only occurs at includes where the alias-property
+		 * is not set), but every include-file now includes the "big build.xml"
+		 */
+		String buildFileName = "bug412809/performance/buildFileHierarchical"; //$NON-NLS-1$
+		long startTime = System.currentTimeMillis();
+		File buildFile = getBuildFile(buildFileName + ".xml"); //$NON-NLS-1$
+		IAntModel model = AntUtil.getAntModel(buildFile.getAbsolutePath(), false, true, true);
+		AntProjectNode project = model.getProjectNode();
+		long endTime = System.currentTimeMillis();
+
+		Assert.assertNotNull(project);
+		// Parsing the file-hierarchy should not take longer than 7.5s
+		long duration = endTime - startTime;
+		// Change this value if it does not fit the performance needs
+		long maxDuration = 7500;
+
+		Assert.assertTrue("Expecting a duration < " + maxDuration + ", but we have " + duration + "ms", duration < maxDuration); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		// Test the rest
+		AntTargetNode[] targets = getAntTargetNodesOfBuildFile(buildFileName);
+
+		String[] expectedTargets = { "deploy", "commonLv1.deploy", "commonLv1.commonLv2.deploySuper", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				"commonLv1.commonLv2.commonLv3.deployLv3", "commonLv1.commonLv2.commonLv3.commonLv4.deployLv4" }; //$NON-NLS-1$ //$NON-NLS-2$
+		// Expected targets
+		Assert.assertEquals(3380, targets.length);
+		// Just test if the mentioned targets are contained
+		for (String expectedTarget : expectedTargets) {
+			assertContains(expectedTarget, targets);
+		}
+	}
+
+	private AntTargetNode[] getAntTargetNodesOfBuildFile(String buildFileName) {
+		File buildFile = getBuildFile(buildFileName + ".xml"); //$NON-NLS-1$
+		AntTargetNode[] targets = AntUtil.getTargets(buildFile.getAbsolutePath());
+		assertTrue(targets != null);
+		return targets;
+	}
+
+	private void assertTargets(AntTargetNode[] targets, String[] expectedTargetNames) {
+		// Before the bugfix, the dependend target (defined in the included file) was not found and the dependencies-check failed
+		int expectedSize = expectedTargetNames.length;
+		assertTrue("Incorrect number of targets retrieved; should be " + expectedSize + " was: " //$NON-NLS-1$ //$NON-NLS-2$
+				+ targets.length, targets.length == expectedSize);
+
+		for (String expectedTarget : expectedTargetNames) {
+			assertContains(expectedTarget, targets);
+		}
+	}
+
 	protected ILaunchConfiguration getLaunchConfiguration(String buildFileName, String arguments, Map<String, String> properties, String propertyFiles) throws CoreException {
 		ILaunchConfiguration config = getLaunchConfiguration(buildFileName);
 		assertNotNull("Could not locate launch configuration for " + buildFileName, config); //$NON-NLS-1$
diff --git a/ant/org.eclipse.ant.tests.ui/pom.xml b/ant/org.eclipse.ant.tests.ui/pom.xml
index 743859d..dda1cad 100644
--- a/ant/org.eclipse.ant.tests.ui/pom.xml
+++ b/ant/org.eclipse.ant.tests.ui/pom.xml
@@ -5,7 +5,7 @@
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
   http://www.eclipse.org/org/documents/edl-v10.php
- 
+
   Contributors:
      Igor Fedorenko - initial implementation
 -->
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchical.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchical.xml
new file mode 100644
index 0000000..83e63ba
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchical.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Specific">
+	<include file="buildFileHierarchicalLv1.xml" as="commonLv1Prefix"/>
+	<target name="deploy" depends="commonLv1Prefix.deploy,
+		commonLv1Prefix.commonLv2Prefix.deploySuper,
+		commonLv1Prefix.commonLv2Prefix.commonLv3Prefix.deployLv3" />
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv1.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv1.xml
new file mode 100644
index 0000000..b9b3fe8
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv1">
+	<include file="buildFileHierarchicalLv2.xml" as="commonLv2Prefix" />
+	<target name="deploy">
+		<echo>test</echo>
+	</target>
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv2.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv2.xml
new file mode 100644
index 0000000..dbef677
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonSuper">
+	<include file="buildFileHierarchicalLv3.xml" as="commonLv3Prefix"/>
+	<target name="deploySuper">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv3.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv3.xml
new file mode 100644
index 0000000..ce0af9d
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv3">
+	<include file="buildFileHierarchicalLv4.xml" as="commonLv4Prefix"/>
+	<target name="deployLv3">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv4.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv4.xml
new file mode 100644
index 0000000..d090e28
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/alias/buildFileHierarchicalLv4.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv4">
+	<target name="deployLv4" >
+		<echo>test-lv4</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchical.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchical.xml
new file mode 100644
index 0000000..2ed49a5
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchical.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Specific">
+
+	<include file="buildFileHierarchicalLv1.xml" />
+	<target name="deploy" depends="commonLv1.deploy,
+    	commonLv1.commonLv2.deploySuper,
+    	commonLv1.commonLv2.commonLv3Prefix.deployLv3" />
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv1.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv1.xml
new file mode 100644
index 0000000..d956b31
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv1">
+	<include file="buildFileHierarchicalLv2.xml" />
+	<target name="deploy">
+		<echo>test</echo>
+	</target>
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv2.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv2.xml
new file mode 100644
index 0000000..80a47b0
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv2">
+	<include file="buildFileHierarchicalLv3.xml" as="commonLv3Prefix"/>
+	<target name="deploySuper">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv3.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv3.xml
new file mode 100644
index 0000000..ce0af9d
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv3">
+	<include file="buildFileHierarchicalLv4.xml" as="commonLv4Prefix"/>
+	<target name="deployLv3">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv4.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv4.xml
new file mode 100644
index 0000000..e243210
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/misc/buildFileHierarchicalLv4.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv4">
+	<target name="deployLv4">
+		<echo>test-lv4</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchical.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchical.xml
new file mode 100644
index 0000000..dec0ef0
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchical.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Specific">
+	<include file="buildFileHierarchicalLv1.xml" />
+	<target name="deploy" depends="commonLv1.deploy,
+    	commonLv1.commonLv2.deploySuper,
+    	commonLv1.commonLv2.commonLv3.deployLv3" />
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv1.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv1.xml
new file mode 100644
index 0000000..64881c1
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv1.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv1">
+	<include file="buildFileHierarchicalLv2.xml"/>
+	<target name="deploy">
+		<echo>test</echo>
+	</target>
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv2.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv2.xml
new file mode 100644
index 0000000..e7e8bec
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv2.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv2">
+	<include file="buildFileHierarchicalLv3.xml"/>
+	<target name="deploySuper" >
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv3.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv3.xml
new file mode 100644
index 0000000..489319b
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv3.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv3">
+	<include file="buildFileHierarchicalLv4.xml"/>
+	<target name="deployLv3">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv4.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv4.xml
new file mode 100644
index 0000000..d090e28
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/complex/noAlias/buildFileHierarchicalLv4.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv4">
+	<target name="deployLv4" >
+		<echo>test-lv4</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchical.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchical.xml
new file mode 100644
index 0000000..984baaa
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchical.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Comment here on purpose. Same with project-tag over multiple lines -->
+<project name="Specific">
+
+	<include file="buildFileHierarchicalLv1.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+
+	<target name="deploy" depends="commonLv1.deploy,
+    	commonLv1.commonLv2.deploySuper,
+    	commonLv1.commonLv2.commonLv3.deployLv3" />
+
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv1.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv1.xml
new file mode 100644
index 0000000..b1d94d7
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv1.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv1">
+	<include file="buildFileHierarchicalLv2.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+
+	<target name="deploy">
+		<echo>test</echo>
+	</target>
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv2.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv2.xml
new file mode 100644
index 0000000..9a5d5bf
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv2">
+	<include file="buildFileHierarchicalLv3.xml"/>
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+
+	<target name="deploySuper" >
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv3.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv3.xml
new file mode 100644
index 0000000..d847545
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv3.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv3">
+	<include file="buildFileHierarchicalLv4.xml"/>
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+
+	<target name="deployLv3">
+		<echo>test-lv3</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv4.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv4.xml
new file mode 100644
index 0000000..2f9138c
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/performance/buildFileHierarchicalLv4.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="commonLv4">
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+	<include file="../../performance/build.xml" />
+
+	<target name="deployLv4" >
+		<echo>test-lv4</echo>
+	</target>
+</project>
\ No newline at end of file
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileAlias.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileAlias.xml
new file mode 100644
index 0000000..30c0014
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileAlias.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Specific">
+
+	<include file="includeFile.xml" as="commonPrefixed" />
+
+	<target name="deploy" depends="commonPrefixed.deploy" />
+
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileNoAlias.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileNoAlias.xml
new file mode 100644
index 0000000..eb2de9b
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/buildFileNoAlias.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Specific">
+
+	<include file="includeFile.xml"/>
+
+	<target name="deploy" depends="common.deploy" />
+
+</project>
diff --git a/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/includeFile.xml b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/includeFile.xml
new file mode 100644
index 0000000..171dcb7
--- /dev/null
+++ b/ant/org.eclipse.ant.tests.ui/testbuildfiles/bug412809/simple/includeFile.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="common">
+	<target name="deploy">
+		<echo>test</echo>
+	</target>
+</project>
diff --git a/ant/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/utils/ProjectHelper.java b/ant/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/utils/ProjectHelper.java
index cce3f11..fa97501 100644
--- a/ant/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/utils/ProjectHelper.java
+++ b/ant/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/utils/ProjectHelper.java
@@ -43,6 +43,7 @@
 import org.apache.tools.ant.util.JAXPUtils;
 import org.eclipse.ant.internal.core.IAntCoreConstants;
 import org.eclipse.ant.internal.ui.model.IAntModel;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.jface.text.BadLocationException;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -90,6 +91,11 @@
 	private static LexicalHandler lexicalHandler = new LexHandler();
 
 	private static XMLReader fgXMLReader = null;
+	/*
+	 * Required to remember the project names (in case they are required for target-prefixing). The build file(s) are parsed anyway and hence the
+	 * project name is added to this map when it gets parsed.
+	 */
+	private static Map<String, String> parsedProjectNames = null;
 
 	public static class ElementHandler extends ProjectHelper2.ElementHandler {
 
@@ -100,7 +106,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -111,7 +117,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -139,7 +145,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String,
 		 * org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -242,7 +248,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext)
 		 */
 		@Override
@@ -269,7 +275,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -289,11 +295,60 @@
 		}
 	}
 
+	/**
+	 * Gets the associated project name by the absolute build-file path
+	 *
+	 * @param buildFile
+	 *            The file
+	 * @return The project name
+	 */
+	public static String getProjectNameOfBuildFile(IFile buildFile) {
+		return parsedProjectNames.get(getBuildFileKey(buildFile));
+	}
+
+	/**
+	 * Builds the hash-map's build-file key
+	 *
+	 * @param buildFile
+	 *            The build file
+	 * @return The key as string
+	 */
+	private static String getBuildFileKey(IFile buildFile) {
+		return buildFile.getLocationURI().getPath();
+	}
+
+	/**
+	 * Adds a parsed project-name to the property-holder (and initializes the collection if necessary)
+	 *
+	 * @param key
+	 *            The key (file-path).
+	 * @param projectName
+	 *            The projectname to add.
+	 */
+	public static void storeParsedProjectName(String key, String projectName) {
+		// init if required
+		if (parsedProjectNames == null) {
+			parsedProjectNames = new HashMap<>();
+		}
+		parsedProjectNames.put(key, projectName);
+	}
+
+	/**
+	 * Clear the parsed project-holder to avoid potential memory leaks.
+	 */
+	public static void clearAdditionalPropertyHolders() {
+		/*
+		 * Currently only this "property-holder" is used. Extend if necessary.
+		 */
+		parsedProjectNames.clear();
+		parsedProjectNames = null;
+	}
+
 	public static class ProjectHandler extends ProjectHelper2.ProjectHandler {
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -308,7 +363,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String,
 		 * org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -323,7 +378,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -331,6 +386,13 @@
 		public void onStartElement(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) {
 			try {
 				super.onStartElement(uri, tag, qname, attrs, context);
+				// add project-name to property holder (if no aliases are used, the project name is required for target prefixing)
+				String currentProjectName = context.getCurrentProjectName();
+				// just an additional check if the name is non-empty
+				if (this.isCurrentProjectNameValid(currentProjectName)) {
+					String buildFilePath = context.getBuildFile().getPath();
+					storeParsedProjectName(buildFilePath, currentProjectName);
+				}
 			}
 			catch (SAXParseException e) {
 				getAntModel().error(e);
@@ -349,9 +411,20 @@
 			}
 		}
 
+		/**
+		 * Checks if the parsed value is a valid project name (i.e. is non-empty: It doesn't make sense to store empty project-names)
+		 *
+		 * @param currentProjectName
+		 *            The current project name
+		 * @return If the given project name is valid or not.
+		 */
+		private boolean isCurrentProjectNameValid(String currentProjectName) {
+			return currentProjectName != null && !currentProjectName.equals(""); //$NON-NLS-1$
+		}
+
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext)
 		 */
 		@Override
@@ -371,7 +444,7 @@
 	public static class TargetHandler extends ProjectHelper2.TargetHandler {
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -382,7 +455,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String,
 		 * org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -411,7 +484,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String,
 		 * org.apache.tools.ant.helper.AntXMLContext)
 		 */
@@ -424,7 +497,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext)
 		 */
 		@Override
@@ -449,7 +522,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
 		 */
 		@Override
@@ -459,7 +532,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
 		 */
 		@Override
@@ -469,7 +542,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
 		 */
 		@Override
@@ -479,7 +552,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
 		 */
 		@Override
@@ -499,7 +572,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
 		 */
 		@Override
@@ -532,7 +605,7 @@
 	private static class LexHandler implements LexicalHandler {
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#endCDATA()
 		 */
 		@Override
@@ -542,7 +615,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#endDTD()
 		 */
 		@Override
@@ -556,7 +629,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#startCDATA()
 		 */
 		@Override
@@ -566,7 +639,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
 		 */
 		@Override
@@ -582,7 +655,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String)
 		 */
 		@Override
@@ -592,7 +665,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String)
 		 */
 		@Override
@@ -607,7 +680,7 @@
 
 		/*
 		 * (non-Javadoc)
-		 * 
+		 *
 		 * @see org.xml.sax.ext.LexicalHandler#startDTD(java.lang.String, java.lang.String, java.lang.String)
 		 */
 		@Override
@@ -629,7 +702,7 @@
 	 * <p>
 	 * This constructor is only to be used by the {@link ProjectHelperRepository} when loading instances of registered helpers.
 	 * </p>
-	 * 
+	 *
 	 * @since 3.7
 	 * @noreference This constructor is not intended to be referenced by clients.
 	 */
@@ -638,7 +711,7 @@
 
 	/**
 	 * Parses the project file, configuring the project as it goes.
-	 * 
+	 *
 	 * @param project
 	 *            the current project
 	 * @param source
@@ -736,7 +809,7 @@
 
 	/**
 	 * Sets the buildfile that is about to be parsed or <code>null</code> if parsing has completed.
-	 * 
+	 *
 	 * @param file
 	 *            The buildfile about to be parsed
 	 */
@@ -748,7 +821,7 @@
 	/*
 	 * (non-Javadoc) We override this method from ProjectHelper2 as we do not want to execute the implicit target or any other target for that matter
 	 * as it could hang Eclipse. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=50795 for more details.
-	 * 
+	 *
 	 * @see org.apache.tools.ant.ProjectHelper#parse(org.apache.tools.ant.Project, java.lang.Object)
 	 */
 	@Override
@@ -820,7 +893,7 @@
 
 	/**
 	 * Returns a newly created SAX 2 XMLReader, which is namespace aware
-	 * 
+	 *
 	 * @return a SAX 2 XMLReader.
 	 * @since Ant 1.6 from org.apache.tools.ant.util.JAXPUtils
 	 */
@@ -838,9 +911,9 @@
 
 	/**
 	 * Returns the parser factory to use to create namespace aware parsers.
-	 * 
+	 *
 	 * @return a SAXParserFactory to use which supports manufacture of namespace aware parsers
-	 * 
+	 *
 	 * @since Ant 1.6 from org.apache.tools.ant.util.JAXPUtils
 	 */
 	private SAXParserFactory getNSParserFactory() throws BuildException {
@@ -853,7 +926,7 @@
 
 	/**
 	 * @return a new SAXParser instance as helper for getParser and getXMLReader.
-	 * 
+	 *
 	 * @since Ant 1.5 from org.apache.tools.ant.util.JAXPUtils
 	 */
 	private SAXParser newSAXParser(SAXParserFactory factory) {
diff --git a/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/IAntUIConstants.java b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/IAntUIConstants.java
index 7339d46..6975e93 100644
--- a/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/IAntUIConstants.java
+++ b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/IAntUIConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     John-Mason P. Shackelford (john-mason.shackelford@pearson.com) - bug 49380, 49445, bug 53547
+ *     Alexander Blaas (arctis Softwaretechnologie GmbH) - bug 412809
  *******************************************************************************/
 package org.eclipse.ant.internal.ui;
 
@@ -24,7 +25,7 @@
 	/**
 	 * Plugin identifier for Ant ui(value <code>org.eclipse.ant.ui</code>).
 	 */
-	public static final String PLUGIN_ID = "org.eclipse.ant.ui"; //$NON-NLS-1$;
+	public static final String PLUGIN_ID = "org.eclipse.ant.ui"; //$NON-NLS-1$ ;
 
 	// ------- Views -------
 
@@ -42,7 +43,7 @@
 	public static final String IMG_PROPERTY = PLUGIN_ID + ".IMG_PROPERTY"; //$NON-NLS-1$
 
 	public static final String IMG_TAB_ANT_TARGETS = PLUGIN_ID + ".IMG_TAB_ANT_TARGETS"; //$NON-NLS-1$
-	public static final String IMG_TAB_CLASSPATH = PLUGIN_ID + ".IMG_TAB_CLASSPATH"; //$NON-NLS-1$;
+	public static final String IMG_TAB_CLASSPATH = PLUGIN_ID + ".IMG_TAB_CLASSPATH"; //$NON-NLS-1$ ;
 
 	// Label images
 	public static final String IMG_ANT = PLUGIN_ID + ".ant"; //$NON-NLS-1$
@@ -53,6 +54,8 @@
 	public static final String IMG_ANT_TARGET_ERROR = PLUGIN_ID + ".antTargetError"; //$NON-NLS-1$
 	public static final String IMG_ANT_MACRODEF = PLUGIN_ID + ".antMacrodef"; //$NON-NLS-1$
 	public static final String IMG_ANT_IMPORT = PLUGIN_ID + ".antImport"; //$NON-NLS-1$
+	// TODO: add a include label image and change the identifier
+	public static final String IMG_ANT_INCLUDE = PLUGIN_ID + ".antImport"; //$NON-NLS-1$
 	public static final String IMG_ANT_TASKDEF = PLUGIN_ID + ".antTaskdef"; //$NON-NLS-1$
 	public static final String IMG_ANT_ECLIPSE_RUNTIME_OBJECT = PLUGIN_ID + ".antEclipse"; //$NON-NLS-1$
 
@@ -104,7 +107,7 @@
 
 	/**
 	 * Size of left-hand column for right-justified task name. Used for Ant Build logging.
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.launching.runtime.logger.AntProcessBuildLogger
 	 * @see org.eclipse.ant.internal.launching.launchConfigurations.RemoteAntBuildListener
 	 */
@@ -118,5 +121,5 @@
 	/**
 	 * Boolean attribute indicating if an input handler should be supplied for the build Default value is <code>true</code>.
 	 */
-	public static final String SET_INPUTHANDLER = PLUGIN_ID + "SET_INPUTHANDLER"; //$NON-NLS-1$	
+	public static final String SET_INPUTHANDLER = PLUGIN_ID + "SET_INPUTHANDLER"; //$NON-NLS-1$
 }
diff --git a/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntIncludeNode.java b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntIncludeNode.java
new file mode 100644
index 0000000..906d54c
--- /dev/null
+++ b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntIncludeNode.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2019 arctis Softwaretechnologie GmbH and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Alexander Blaas (arctis Softwaretechnologie GmbH) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ant.internal.ui.model;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.Task;
+import org.eclipse.ant.core.AntSecurityException;
+import org.eclipse.ant.internal.ui.AntUIImages;
+import org.eclipse.ant.internal.ui.IAntUIConstants;
+import org.eclipse.ant.internal.ui.preferences.AntEditorPreferenceConstants;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.xml.sax.Attributes;
+
+public class AntIncludeNode extends AntImportNode {
+
+	public AntIncludeNode(Task task, Attributes attributes) {
+		super(task, attributes);
+	}
+
+	@Override
+	protected ImageDescriptor getBaseImageDescriptor() {
+		// TODO: set an include-descriptor
+		return AntUIImages.getImageDescriptor(IAntUIConstants.IMG_ANT_INCLUDE);
+	}
+
+	/**
+	 * Execute the import. Returns <code>true</code> as the import adds to the Ant model
+	 */
+	@Override
+	public boolean configure(boolean validateFully) {
+		if (fConfigured) {
+			return false;
+		}
+
+		try {
+			getTask().maybeConfigure();
+			// Get the node where the import happened.
+			AntTaskNode importedFromNode = (AntTaskNode) getImportNode();
+			// ImportNode is null => include happened from the top-file.
+			if (importedFromNode != null) {
+				String currentPrefix = this.getIncludePrefix(importedFromNode);
+				ProjectHelper.setCurrentTargetPrefix(currentPrefix);
+			} else {
+				// Reset the currentTargetPrefix if the include-task has no import node.
+				ProjectHelper.setCurrentTargetPrefix(null);
+			}
+
+			getTask().execute();
+			fConfigured = true;
+			return true;
+		}
+		catch (BuildException be) {
+			handleBuildException(be, AntEditorPreferenceConstants.PROBLEM_IMPORTS);
+		}
+		catch (AntSecurityException se) {
+			// Either a system exit or setting of system property was attempted.
+			handleBuildException(new BuildException(AntModelMessages.AntImportNode_0), AntEditorPreferenceConstants.PROBLEM_SECURITY);
+		}
+		return false;
+	}
+
+	/**
+	 * Gets the include prefix among the whole "include-hierarchy".
+	 *
+	 * @param startNode
+	 *            The node where to start.
+	 *
+	 * @return The complete include-prefix.
+	 */
+	private String getIncludePrefix(AntTaskNode startNode) {
+		AntTaskNode actualNode = startNode;
+		StringBuilder builder = new StringBuilder();
+		while (actualNode != null) {
+			// Supposed to be non-null.
+			String actualPrefixSeparator = ProjectHelper.getCurrentPrefixSeparator();
+			String actualPrefix = this.getIncludePrefixSingleNode(actualNode);
+
+			if (actualPrefix != null) {
+				// Iteration happens in reverse order => prepend.
+				builder.insert(0, actualPrefix + actualPrefixSeparator);
+			}
+			actualNode = (AntTaskNode) actualNode.getImportNode();
+		}
+		// Remove last separator.
+		if (builder.length() > 0) {
+			builder.deleteCharAt(builder.length() - 1);
+		}
+		return builder.toString();
+	}
+
+	/**
+	 * Extracts the include prefix (currentTargetPrefix) for nested includes.
+	 *
+	 * @param importedFromNode
+	 *            The node where the import belongs to.
+	 * @return The include prefix or null.
+	 */
+	private String getIncludePrefixSingleNode(AntTaskNode importedFromNode) {
+		Object asPropValue = importedFromNode.getTask().getRuntimeConfigurableWrapper().getAttributeMap().get("as"); //$NON-NLS-1$
+		String includePrefix = (asPropValue != null ? asPropValue.toString() : null);
+
+		// It may happen, that an include hasn't set the "as" attribute => the prefix needs to be retrieved elsewhere.
+		if (includePrefix == null) {
+			/*
+			 * When the current build-file is parsed, its project-name is stored at a property-holder (see
+			 * org.eclipse.ant.internal.ui.editor.utils.ProjectHelper) and associated with the current build-file's absolute path. To get the required
+			 * project-name, just a lookup at the mentioned property-holder is required.
+			 */
+			includePrefix = this.extractProjectNameSingleNode(importedFromNode);
+		}
+		return includePrefix;
+	}
+
+	/**
+	 * Retrieves the project name of the associated build-file by doing a lookup at a property-holder.
+	 *
+	 * @param importedFromNode
+	 *            The node where the import belongs to.
+	 * @return The project name or null if not existent.
+	 */
+	private String extractProjectNameSingleNode(AntTaskNode importedFromNode) {
+		/*
+		 * Retrieve correct file: An AntIncludeNode has the properties fFile and fFilePath. It seems, that the "fFile" property holds the path where
+		 * the actual build-file is located (desired). But the "fFilePath" property points to another location (enclosing include-file?). Which file
+		 * is retrieved after calling getIFile(), depends on the isExternal property. If it is set to false, the desired file is returned.
+		 *
+		 * => The property isExternal is temporary set to false and restored after the file could be retrieved. This should guarantee the correctness
+		 * of any subsequent operation on the AntIncludeNode object.
+		 */
+		IFile projectSpecificBuildFile = this.handleCorrectBuildFile(importedFromNode);
+		return org.eclipse.ant.internal.ui.editor.utils.ProjectHelper.getProjectNameOfBuildFile(projectSpecificBuildFile);
+	}
+
+	/**
+	 * If the isExternal-property is set to true, the wrong file is returned (the parent-file of the include?). To avoid this, the isExternal-property
+	 * is temporary set to false and restore afterwards to guarantee correct subsequent processing.
+	 *
+	 * @param importedFromNode
+	 *            The importedNode.
+	 * @return The correct file.
+	 */
+	private IFile handleCorrectBuildFile(AntTaskNode importedFromNode) {
+		Boolean isExternal = null;
+		try {// Save property.
+			isExternal = importedFromNode.isExternal();
+			// External needs to be false? Otherwise the wrong file gets loaded...
+			importedFromNode.setExternal(false);
+			// Retrieve correct file.
+			return importedFromNode.getIFile();
+		}
+		finally {
+			// Restore the isExternal property after returning the correct file.
+			importedFromNode.setExternal(isExternal);
+		}
+	}
+}
diff --git a/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java
index 3af20b1..5c694ac 100644
--- a/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java
+++ b/ant/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,10 +7,11 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Nico Seessle - bug 51332
+ *     Alexander Blaas (arctis Softwaretechnologie GmbH) - bug 412809
  *******************************************************************************/
 
 package org.eclipse.ant.internal.ui.model;
@@ -219,7 +220,7 @@
 
 	/**
 	 * Searches the collection of registered {@link org.apache.tools.ant.ProjectHelper}s to see if we have one registered already.
-	 * 
+	 *
 	 * @return the {@link ProjectHelper} from our implementation of <code>null</code> if we have not registered one yet
 	 * @since 3.7
 	 * @see ProjectHelperRepository
@@ -237,7 +238,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#dispose()
 	 */
 	@Override
@@ -291,7 +292,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#reconcile()
 	 */
 	@Override
@@ -381,6 +382,8 @@
 					System.setSecurityManager(new AntSecurityManager(origSM, Thread.currentThread(), false));
 					resolveBuildfile();
 					endReporting();
+					// clear the additional property-holder(s) to avoid potential memory leaks
+					ProjectHelper.clearAdditionalPropertyHolders();
 				}
 				catch (AntSecurityException e) {
 					// do nothing
@@ -678,7 +681,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#handleBuildException(org.apache.tools.ant.BuildException,
 	 * org.eclipse.ant.internal.ui.model.AntElementNode, int)
 	 */
@@ -746,7 +749,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getEditedFile()
 	 */
 	@Override
@@ -770,7 +773,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getLocationProvider()
 	 */
 	@Override
@@ -780,7 +783,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addTarget(org.apache.tools.ant.Target, int, int)
 	 */
 	@Override
@@ -806,7 +809,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addProject(org.apache.tools.ant.Project, int, int)
 	 */
 	@Override
@@ -818,7 +821,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addDTD(java.lang.String, int, int)
 	 */
 	@Override
@@ -844,7 +847,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addTask(org.apache.tools.ant.Task, org.apache.tools.ant.Task, org.xml.sax.Attributes, int,
 	 * int)
 	 */
@@ -892,7 +895,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addEntity(java.lang.String, java.lang.String)
 	 */
 	@Override
@@ -915,6 +918,8 @@
 			newNode = new AntPropertyNode(newTask, attributes);
 		} else if (taskName.equalsIgnoreCase("import")) { //$NON-NLS-1$
 			newNode = new AntImportNode(newTask, attributes);
+		} else if (taskName.equalsIgnoreCase("include")) { //$NON-NLS-1$
+			newNode = new AntIncludeNode(newTask, attributes);
 		} else if (taskName.equalsIgnoreCase("macrodef") //$NON-NLS-1$
 				|| taskName.equalsIgnoreCase("presetdef") //$NON-NLS-1$
 				|| taskName.equalsIgnoreCase("typedef") //$NON-NLS-1$
@@ -1119,7 +1124,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getOffset(int, int)
 	 */
 	@Override
@@ -1152,7 +1157,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#setCurrentElementLength(int, int)
 	 */
 	@Override
@@ -1177,7 +1182,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getFile()
 	 */
 	@Override
@@ -1241,7 +1246,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#warning(java.lang.Exception)
 	 */
 	@Override
@@ -1251,7 +1256,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#error(java.lang.Exception)
 	 */
 	@Override
@@ -1261,7 +1266,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#errorFromElementText(java.lang.Exception, int, int)
 	 */
 	@Override
@@ -1282,7 +1287,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#errorFromElement(java.lang.Exception, org.eclipse.ant.internal.ui.model.AntElementNode, int,
 	 * int)
 	 */
@@ -1429,7 +1434,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#fatalError(java.lang.Exception)
 	 */
 	@Override
@@ -1446,7 +1451,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getEntityName(java.lang.String)
 	 */
 	@Override
@@ -1511,7 +1516,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getProjectNode(boolean)
 	 */
 	@Override
@@ -1526,7 +1531,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getProjectNode()
 	 */
 	@Override
@@ -1574,7 +1579,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addComment(int, int, int)
 	 */
 	@Override
@@ -1596,7 +1601,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#needsTaskResolution()
 	 */
 	@Override
@@ -1606,7 +1611,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#needsLexicalResolution()
 	 */
 	@Override
@@ -1616,7 +1621,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#setClassLoader(java.net.URLClassLoader)
 	 */
 	@Override
@@ -1627,7 +1632,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#needsPositionResolution()
 	 */
 	@Override
@@ -1651,7 +1656,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getText(int, int)
 	 */
 	@Override
@@ -1795,7 +1800,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#setProperties(java.util.Map)
 	 */
 	@Override
@@ -1805,7 +1810,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#setPropertyFiles(java.util.List)
 	 */
 	@Override
@@ -1924,7 +1929,7 @@
 
 	/**
 	 * Sets whether the AntModel should reconcile if it become dirty. If set to reconcile, a reconcile is triggered if the model is dirty.
-	 * 
+	 *
 	 * @param shouldReconcile
 	 */
 	public void setShouldReconcile(boolean shouldReconcile) {
@@ -1936,7 +1941,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#addPrefixMapping(java.lang.String, java.lang.String)
 	 */
 	@Override
@@ -1970,7 +1975,7 @@
 
 	/**
 	 * Compute the encoding for the backing build file
-	 * 
+	 *
 	 * @since 3.7
 	 */
 	void computeEncoding() {
@@ -2005,7 +2010,7 @@
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.eclipse.ant.internal.ui.model.IAntModel#getEncoding()
 	 */
 	@Override