Add ctx.ModuleDir and top level module dirs of input sources to JDK9
--patch-module lookup.

javac --patch-module accepts a list of directories and/or jars for JDK9
module patching (see bug for more details). In Bazel-Ninja execution,
Bazel executes the javac action in its own execution root working
directory, unlike Ninja, which works in the Android top level directory.
The Bazel execution root is formed of a symlink forest of top level
directories. This symlink forest is a problem for javac because it
doesn't traverse into symlinks.

To support Bazel executing these javac actions, we explicitly encode the
module directory, and the top level directory of any other source file
inputs into the --patch-module javac flag.

For example, the "core-all" libcore module compiles into `java.base`,
and depends on filegroups outside of `libcore` (`tools`). This CL adds
`tools` to the --patch-module lookup dir, on top of `libcore`.

See java_test.go for more details.

Bug: 150878007
Fixes: 150878007
Test: m
Test: bazel build droid (aosp_flame)
Change-Id: Id95b0a9a675fc75678f7b5e600344b4403f0c518
diff --git a/java/java.go b/java/java.go
index 3167512..9f09051 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1246,7 +1246,8 @@
 	return flags
 }
 
-func (j *Module) collectJavacFlags(ctx android.ModuleContext, flags javaBuilderFlags) javaBuilderFlags {
+func (j *Module) collectJavacFlags(
+	ctx android.ModuleContext, flags javaBuilderFlags, srcFiles android.Paths) javaBuilderFlags {
 	// javac flags.
 	javacFlags := j.properties.Javacflags
 
@@ -1262,14 +1263,48 @@
 
 		if j.properties.Patch_module != nil {
 			// Manually specify build directory in case it is not under the repo root.
-			// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
+			// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
 			// just adding a symlink under the root doesn't help.)
-			patchPaths := ".:" + ctx.Config().BuildDir()
+			patchPaths := []string{".", ctx.Config().BuildDir()}
+
+			// b/150878007
+			//
+			// Workaround to support *Bazel-executed* JDK9 javac in Bazel's
+			// execution root for --patch-module. If this javac command line is
+			// invoked within Bazel's execution root working directory, the top
+			// level directories (e.g. libcore/, tools/, frameworks/) are all
+			// symlinks. JDK9 javac does not traverse into symlinks, which causes
+			// --patch-module to fail source file lookups when invoked in the
+			// execution root.
+			//
+			// Short of patching javac or enumerating *all* directories as possible
+			// input dirs, manually add the top level dir of the source files to be
+			// compiled.
+			topLevelDirs := map[string]bool{}
+			for _, srcFilePath := range srcFiles {
+				srcFileParts := strings.Split(srcFilePath.String(), "/")
+				// Ignore source files that are already in the top level directory
+				// as well as generated files in the out directory. The out
+				// directory may be an absolute path, which means srcFileParts[0] is the
+				// empty string, so check that as well. Note that "out" in Bazel's execution
+				// root is *not* a symlink, which doesn't cause problems for --patch-modules
+				// anyway, so it's fine to not apply this workaround for generated
+				// source files.
+				if len(srcFileParts) > 1 &&
+					srcFileParts[0] != "" &&
+					srcFileParts[0] != "out" {
+					topLevelDirs[srcFileParts[0]] = true
+				}
+			}
+			patchPaths = append(patchPaths, android.SortedStringKeys(topLevelDirs)...)
+
 			classPath := flags.classpath.FormJavaClassPath("")
 			if classPath != "" {
-				patchPaths += ":" + classPath
+				patchPaths = append(patchPaths, classPath)
 			}
-			javacFlags = append(javacFlags, "--patch-module="+String(j.properties.Patch_module)+"="+patchPaths)
+			javacFlags = append(
+				javacFlags,
+				"--patch-module="+String(j.properties.Patch_module)+"="+strings.Join(patchPaths, ":"))
 		}
 	}
 
@@ -1303,7 +1338,9 @@
 
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
-	flags = j.collectJavacFlags(ctx, flags)
+	// Collect javac flags only after computing the full set of srcFiles to
+	// ensure that the --patch-module lookup paths are complete.
+	flags = j.collectJavacFlags(ctx, flags, srcFiles)
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
diff --git a/java/java_test.go b/java/java_test.go
index cdb4375..6c0a908 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2046,7 +2046,14 @@
 
 			java_library {
 				name: "baz",
-				srcs: ["c.java"],
+				srcs: [
+					"c.java",
+					// Tests for b/150878007
+					"dir/d.java",
+					"dir2/e.java",
+					"dir2/f.java",
+					"nested/dir/g.java"
+				],
 				patch_module: "java.base",
 			}
 		`
@@ -2055,7 +2062,8 @@
 		checkPatchModuleFlag(t, ctx, "foo", "")
 		expected := "java.base=.:" + buildDir
 		checkPatchModuleFlag(t, ctx, "bar", expected)
-		expected = "java.base=" + strings.Join([]string{".", buildDir, moduleToPath("ext"), moduleToPath("framework")}, ":")
+		expected = "java.base=" + strings.Join([]string{
+			".", buildDir, "dir", "dir2", "nested", moduleToPath("ext"), moduleToPath("framework")}, ":")
 		checkPatchModuleFlag(t, ctx, "baz", expected)
 	})
 }