Support fully qualified names in `android:"path"` properties

Previously, a module reference in a path property would be parsed into
two parts, the module name and the optional output tag, which defaults
to an empty string if not specified. The output tag would be stored in
a sourceOrOutputDependencyTag which would then be used, along with the
module name to add a dependency on the module.

Later, when the paths were processed the same module reference would be
parsed into the same two parts again and the module name used to find a
matching Module by comparing it against the name returned by either
Module.Name(), ctx.OtherModuleName() or ModuleBase.BaseModuleName().
Once the module had been found then if it supported OutputFilesProducer
then the tag would be passed to its OutputFiles(tag) method. Otherwise,
it would fall back to treating it as SourceFilesProducer.

The problem with that is the module name retrieved from the module in
some way (either directly or through a context name) could be different
to that originally supplied when adding the dependency. e.g.
1. If the original dependency was added onto a source module but there
   existed a suitable and preferred prebuilt module then the dependency
   onto the source module would have been replaced by the prebuilt
   module which has a different name.
2. If the path property included a fully qualified name that included
   a qualifying path then it would not match the name retrieved from
   the module which would not include the qualifying path.

This change circumvents that whole issue by adding the module name that
was originally used to add the dependency into the DependencyTag. Now
the DependencyTag uniquely identifies the original module/outputTag
pair parsed from the module reference. The pathDepsMutator guarantees
that they are unique as it dedups them before adding the dependencies.

It is possible that calling ExtractSource(s)Deps() would add some
duplicate but if they did they would be identical, i.e. the same
sourceOrOutputDependencyTag would be used to add a dependency onto the
exact same module. In that case it would not matter which of the
dependencies was found as it would still return the same module.

Bug: 193228441
Test: m nothing
Change-Id: I661514a2984818e5c26577411cede53eb57bcd02
diff --git a/android/module.go b/android/module.go
index 126d629..385b63a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2865,18 +2865,31 @@
 	return strings.IndexByte(module, '/') == -1
 }
 
+// sourceOrOutputDependencyTag is the dependency tag added automatically by pathDepsMutator for any
+// module reference in a property annotated with `android:"path"` or passed to ExtractSourceDeps
+// or ExtractSourcesDeps.
+//
+// If uniquely identifies the dependency that was added as it contains both the module name used to
+// add the dependency as well as the tag. That makes it very simple to find the matching dependency
+// in GetModuleFromPathDep as all it needs to do is find the dependency whose tag matches the tag
+// used to add it. It does not need to check that the module name as returned by one of
+// Module.Name(), BaseModuleContext.OtherModuleName() or ModuleBase.BaseModuleName() matches the
+// name supplied in the tag. That means it does not need to handle differences in module names
+// caused by prebuilt_ prefix, or fully qualified module names.
 type sourceOrOutputDependencyTag struct {
 	blueprint.BaseDependencyTag
+
+	// The name of the module.
+	moduleName string
+
+	// The tag that will be passed to the module's OutputFileProducer.OutputFiles(tag) method.
 	tag string
 }
 
-func sourceOrOutputDepTag(tag string) blueprint.DependencyTag {
-	return sourceOrOutputDependencyTag{tag: tag}
+func sourceOrOutputDepTag(moduleName, tag string) blueprint.DependencyTag {
+	return sourceOrOutputDependencyTag{moduleName: moduleName, tag: tag}
 }
 
-// Deprecated, use IsSourceDepTagWithOutputTag(tag, "") instead.
-var SourceDepTag = sourceOrOutputDepTag("")
-
 // IsSourceDepTag returns true if the supplied blueprint.DependencyTag is one that was used to add
 // dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for properties
 // tagged with `android:"path"`.
@@ -2907,7 +2920,7 @@
 				ctx.ModuleErrorf("found source dependency duplicate: %q!", s)
 			} else {
 				set[s] = true
-				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 			}
 		}
 	}
@@ -2920,7 +2933,7 @@
 func ExtractSourceDeps(ctx BottomUpMutatorContext, s *string) {
 	if s != nil {
 		if m, t := SrcIsModuleWithTag(*s); m != "" {
-			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 		}
 	}
 }
diff --git a/android/path_properties.go b/android/path_properties.go
index 4446773..3976880 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -51,7 +51,7 @@
 	// Add dependencies to anything that is a module reference.
 	for _, s := range pathProperties {
 		if m, t := SrcIsModuleWithTag(s); m != "" {
-			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(t), m)
+			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m)
 		}
 	}
 }
diff --git a/android/paths.go b/android/paths.go
index 99d5ba7..bec8a51 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -88,7 +88,8 @@
 // the Path methods that rely on module dependencies having been resolved.
 type ModuleWithDepsPathContext interface {
 	EarlyModulePathContext
-	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
 }
 
 // ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
@@ -484,10 +485,27 @@
 //
 // If tag is "" then the returned module will be the dependency that was added for ":moduleName".
 // Otherwise, it is the dependency that was added for ":moduleName{tag}".
-//
-// TODO(b/193228441) Make this handle fully qualified names, e.g. //namespace:moduleName.
 func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) blueprint.Module {
-	return ctx.GetDirectDepWithTag(moduleName, sourceOrOutputDepTag(tag))
+	var found blueprint.Module
+	// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
+	// module name and the tag. Dependencies added automatically for properties tagged with
+	// `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
+	// dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
+	// it will always be the case that the dependencies will be identical, i.e. the same tag and same
+	// moduleName referring to the same dependency module.
+	//
+	// It does not matter whether the moduleName is a fully qualified name or if the module
+	// dependency is a prebuilt module. All that matters is the same information is supplied to
+	// create the tag here as was supplied to create the tag when the dependency was added so that
+	// this finds the matching dependency module.
+	expectedTag := sourceOrOutputDepTag(moduleName, tag)
+	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		depTag := ctx.OtherModuleDependencyTag(module)
+		if depTag == expectedTag {
+			found = module
+		}
+	})
+	return found
 }
 
 // PathsAndMissingDepsForModuleSrcExcludes returns a Paths{} containing the resolved references in
diff --git a/android/paths_test.go b/android/paths_test.go
index 7675905..f4e4ce1 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1390,7 +1390,6 @@
 			}),
 		},
 		{
-			// TODO(b/193228441): Fix broken test.
 			name: "output file provider, fully qualified name",
 			bp: `
 			test {
@@ -1398,6 +1397,10 @@
 				src: "//other:b",
 				srcs: ["//other:c"],
 			}`,
+			src:  "out/soong/.intermediates/other/b/gen/b",
+			rel:  "gen/b",
+			srcs: []string{"out/soong/.intermediates/other/c/gen/c"},
+			rels: []string{"gen/c"},
 			preparer: FixtureAddTextFile("other/Android.bp", `
 				soong_namespace {}
 
@@ -1411,10 +1414,6 @@
 					outs: ["gen/c"],
 				}
 			`),
-			errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{
-				`"foo": missing dependencies: //other:b, is the property annotated with android:"path"`,
-				`"foo": missing dependency on "//other:c", is the property annotated with android:"path"`,
-			}),
 		},
 	}