Bug 377850 - Error "type X collides with a package" should not be raised
if no compilation units declare the package

Change-Id: I71932eea45b72258e38f1c2ea6c0e361384f61a0
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/PackageTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/PackageTests.java
index 11340bb..9663c2c 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/PackageTests.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/PackageTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -39,7 +39,7 @@
 	/**
 	 * Bugs 6564
 	 */
-	public void testPackageProblem() throws JavaModelException {
+	public void testNoPackageProblem() throws JavaModelException {
 		//----------------------------
 		//           Step 1
 		//----------------------------
@@ -91,7 +91,7 @@
 	/**
 	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=251690
 	 */
-	public void testNoPackageProblem() throws JavaModelException {
+	public void testPackageProblem() throws JavaModelException {
 		IPath projectPath = env.addProject("Project"); //$NON-NLS-1$
 		env.addExternalJars(projectPath, Util.getJavaClassLibs());
 		env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$
@@ -114,6 +114,51 @@
 			new Problem("", "The declared package \"\" does not match the expected package \"p.A\"", bPath, 0, 1, CategorizedProblem.CAT_INTERNAL, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
+	public void testNoFolderProblem() throws JavaModelException {
+		IPath projectPath = env.addProject("Project"); //$NON-NLS-1$
+		env.addExternalJars(projectPath, Util.getJavaClassLibs());
+		env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$
+		IPath src = env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$
+		env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$
+
+		env.addClass(src, "p", "A", //$NON-NLS-1$ //$NON-NLS-2$
+			"package p;\n"+ //$NON-NLS-1$
+			"public class A {}" //$NON-NLS-1$
+		);
+
+		// create folder & contained non-java file (which don't establish package p.A!):
+		env.addFolder(src, "p/A"); //$NON-NLS-1$
+		env.addFile(src, "p/A/some.properties", //$NON-NLS-1$
+			"name=Some\n" //$NON-NLS-1$
+		);
+
+		fullBuild();
+		expectingNoProblems();
+	}
+
+	public void testNestedPackageProblem() throws JavaModelException {
+		IPath projectPath = env.addProject("Project"); //$NON-NLS-1$
+		env.addExternalJars(projectPath, Util.getJavaClassLibs());
+		env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$
+		IPath src = env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$
+		env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$
+
+		IPath aPath = env.addClass(src, "p", "A", //$NON-NLS-1$ //$NON-NLS-2$
+			"package p;\n"+ //$NON-NLS-1$
+			"public class A {}\n" //$NON-NLS-1$
+		);
+
+		// a class in a sub-package of p.A seems to establish package p.A, too, causing a conflict indeed:
+		env.addClass(src, "p.A.c", "B", //$NON-NLS-1$ //$NON-NLS-2$
+			"package p.A.c;\n" +
+			"public class B {}\n" //$NON-NLS-1$
+		);
+
+		fullBuild();
+		expectingOnlySpecificProblemFor(aPath,
+			new Problem("", "The type A collides with a package", aPath, 24, 25, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=117092
 // simplistic linked subfolder used as package, external case (not in workspace)
 public void test001() throws CoreException {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
index 012a927..cbbf20e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -97,6 +97,7 @@
 	}
 	return null;
 }
+/** Lists all java-like files and also sub-directories (for recursive tests). */
 String[] directoryList(String qualifiedPackageName) {
 	String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName);
 	if (dirList == this.missingPackageHolder) return null; // package exists in another classpath directory or jar
@@ -111,7 +112,8 @@
 			for (int i = 0, l = members.length; i < l; i++) {
 				IResource m = members[i];
 				String name = m.getName();
-				if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
+				if (m.getType() == IResource.FOLDER || // include folders so we recognize empty parent packages
+						(m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name))) {
 					// add exclusion pattern check here if we want to hide .class files
 					dirList[index++] = name;
 				}
@@ -215,7 +217,17 @@
 		if (this.module == null || !moduleName.equals(String.valueOf(this.module.name())))
 			return false;
 	}
-	return directoryList(qualifiedPackageName) != null;
+	String[] list = directoryList(qualifiedPackageName);
+	if (list != null) {
+		for (String entry : list) {
+			String entryLC = entry.toLowerCase();
+			if (entryLC.endsWith(SuffixConstants.SUFFIX_STRING_class) || entryLC.endsWith(SuffixConstants.SUFFIX_STRING_java))
+				return true;
+			if (entryLC.indexOf('.') == -1)
+				return isPackage(qualifiedPackageName+'/'+entry, null/*already checked*/);
+		}
+	}
+	return false;
 }
 @Override
 public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
index fd384f2..b72832d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -86,7 +86,8 @@
 				for (int i = 0, l = members.length; i < l; i++) {
 					IResource m = members[i];
 					String name = m.getName();
-					if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
+					if (m.getType() == IResource.FOLDER
+							|| (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name))) {
 						// add exclusion pattern check here if we want to hide .class files
 						dirList[index++] = name;
 					}
@@ -102,7 +103,8 @@
 						for (int i = 0, l = members.length; i < l; i++) {
 							IResource m = members[i];
 							String name = m.getName();
-							if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(name)) {
+							if (m.getType() == IResource.FOLDER
+									|| (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(name))) {
 								// FIXME: check if .java file has any declarations?
 								dirList[index++] = name;
 							}