Use bazel syntax for fully qualified name in path property

A module reference to a fully qualified module in a path property looks
like:
  //path:module
And with a tag:
  //path:module{tag}

At the moment the checking is quite lax but some follow up changes will
make it much stricter.

Bug: 193228441
Test: m nothing
Change-Id: Ie42edcfa33ec66fda5d75b3df1da73f56f147afd
diff --git a/android/module.go b/android/module.go
index ef319a4..e9ad987 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2807,30 +2807,57 @@
 	return m.bp
 }
 
-// SrcIsModule decodes module references in the format ":name" into the module name, or empty string if the input
-// was not a module reference.
+// SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name"
+// into the module name, or empty string if the input was not a module reference.
 func SrcIsModule(s string) (module string) {
-	if len(s) > 1 && s[0] == ':' {
-		return s[1:]
+	if len(s) > 1 {
+		if s[0] == ':' {
+			module = s[1:]
+			if !isUnqualifiedModuleName(module) {
+				// The module name should be unqualified but is not so do not treat it as a module.
+				module = ""
+			}
+		} else if s[0] == '/' && s[1] == '/' {
+			module = s
+		}
 	}
-	return ""
+	return module
 }
 
-// SrcIsModule decodes module references in the format ":name{.tag}" into the module name and tag, ":name" into the
-// module name and an empty string for the tag, or empty strings if the input was not a module reference.
+// SrcIsModule decodes module references in the format ":unqualified-name{.tag}" or
+// "//namespace:name{.tag}" into the module name and an empty string for the tag, or empty strings
+// if the input was not a module reference.
 func SrcIsModuleWithTag(s string) (module, tag string) {
-	if len(s) > 1 && s[0] == ':' {
-		module = s[1:]
-		if tagStart := strings.IndexByte(module, '{'); tagStart > 0 {
-			if module[len(module)-1] == '}' {
-				tag = module[tagStart+1 : len(module)-1]
-				module = module[:tagStart]
-				return module, tag
+	if len(s) > 1 {
+		if s[0] == ':' {
+			module = s[1:]
+		} else if s[0] == '/' && s[1] == '/' {
+			module = s
+		}
+
+		if module != "" {
+			if tagStart := strings.IndexByte(module, '{'); tagStart > 0 {
+				if module[len(module)-1] == '}' {
+					tag = module[tagStart+1 : len(module)-1]
+					module = module[:tagStart]
+				}
+			}
+
+			if s[0] == ':' && !isUnqualifiedModuleName(module) {
+				// The module name should be unqualified but is not so do not treat it as a module.
+				module = ""
+				tag = ""
 			}
 		}
-		return module, ""
 	}
-	return "", ""
+
+	return module, tag
+}
+
+// isUnqualifiedModuleName makes sure that the supplied module is an unqualified module name, i.e.
+// does not contain any /.
+func isUnqualifiedModuleName(module string) bool {
+	return strings.IndexByte(module, '/') == -1
 }
 
 type sourceOrOutputDependencyTag struct {
diff --git a/android/module_test.go b/android/module_test.go
index 9ac9291..9e2b0ca 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -55,6 +55,27 @@
 			},
 			wantModule: "foo:bar",
 		},
+		{
+			name: "fully qualified",
+			args: args{
+				s: "//foo:bar",
+			},
+			wantModule: "//foo:bar",
+		},
+		{
+			name: "fully qualified with tag",
+			args: args{
+				s: "//foo:bar{.tag}",
+			},
+			wantModule: "//foo:bar{.tag}",
+		},
+		{
+			name: "invalid unqualified name",
+			args: args{
+				s: ":foo/bar",
+			},
+			wantModule: "",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -128,6 +149,35 @@
 			},
 			wantModule: "foo.bar}",
 		},
+		{
+			name: "fully qualified",
+			args: args{
+				s: "//foo:bar",
+			},
+			wantModule: "//foo:bar",
+		},
+		{
+			name: "fully qualified with tag",
+			args: args{
+				s: "//foo:bar{.tag}",
+			},
+			wantModule: "//foo:bar",
+			wantTag:    ".tag",
+		},
+		{
+			name: "invalid unqualified name",
+			args: args{
+				s: ":foo/bar",
+			},
+			wantModule: "",
+		},
+		{
+			name: "invalid unqualified name with tag",
+			args: args{
+				s: ":foo/bar{.tag}",
+			},
+			wantModule: "",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/android/paths_test.go b/android/paths_test.go
index 4c18cfd..7675905 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1351,7 +1351,6 @@
 		{
 			// This test makes sure that an unqualified module name cannot contain characters that make
 			// it appear as a qualified module name.
-			// TODO(b/193228441): Fix broken test.
 			name: "output file provider, invalid fully qualified name",
 			bp: `
 			test {
@@ -1372,13 +1371,12 @@
 					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"`,
-			}),
+			src:  "foo/:/other:b",
+			rel:  ":/other:b",
+			srcs: []string{"foo/:/other:c"},
+			rels: []string{":/other:c"},
 		},
 		{
-			// TODO(b/193228441): Fix broken test.
 			name: "output file provider, missing fully qualified name",
 			bp: `
 			test {
@@ -1386,13 +1384,9 @@
 				src: "//other:b",
 				srcs: ["//other:c"],
 			}`,
-			src:  "foo",
-			rel:  "foo",
-			srcs: []string{"foo"},
-			rels: []string{"foo"},
 			errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{
-				`"foo": Path is outside directory: /other:b`,
-				`"foo": Path is outside directory: /other:c`,
+				`"foo" depends on undefined module "//other:b"`,
+				`"foo" depends on undefined module "//other:c"`,
 			}),
 		},
 		{
@@ -1417,13 +1411,9 @@
 					outs: ["gen/c"],
 				}
 			`),
-			src:  "foo",
-			rel:  "foo",
-			srcs: []string{"foo"},
-			rels: []string{"foo"},
 			errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{
-				`"foo": Path is outside directory: /other:b`,
-				`"foo": Path is outside directory: /other:c`,
+				`"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"`,
 			}),
 		},
 	}