Support restrictions based on a module's dependencies

Adds a neverallow InDirectDeps(deps) verb that will allow a neverallow
rule to restrict access to a specific dependency, irrespective of how
it is specified.

Bug: 137543088
Test: m nothing
Change-Id: I0c6bb702d55175e9b78b79e86e96924c5dd83efa
diff --git a/android/neverallow.go b/android/neverallow.go
index 23b6454..be396fc 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -189,6 +189,10 @@
 			continue
 		}
 
+		if !n.appliesToDirectDeps(ctx) {
+			continue
+		}
+
 		ctx.ModuleErrorf("violates " + n.String())
 	}
 }
@@ -246,6 +250,8 @@
 
 	NotIn(path ...string) Rule
 
+	InDirectDeps(deps ...string) Rule
+
 	ModuleType(types ...string) Rule
 
 	NotModuleType(types ...string) Rule
@@ -268,6 +274,8 @@
 	paths       []string
 	unlessPaths []string
 
+	directDeps map[string]bool
+
 	moduleTypes       []string
 	unlessModuleTypes []string
 
@@ -277,7 +285,7 @@
 
 // Create a new NeverAllow rule.
 func NeverAllow() Rule {
-	return &rule{}
+	return &rule{directDeps: make(map[string]bool)}
 }
 
 func (r *rule) In(path ...string) Rule {
@@ -290,6 +298,13 @@
 	return r
 }
 
+func (r *rule) InDirectDeps(deps ...string) Rule {
+	for _, d := range deps {
+		r.directDeps[d] = true
+	}
+	return r
+}
+
 func (r *rule) ModuleType(types ...string) Rule {
 	r.moduleTypes = append(r.moduleTypes, types...)
 	return r
@@ -356,6 +371,9 @@
 	for _, v := range r.unlessProps {
 		s += " -" + strings.Join(v.fields, ".") + v.matcher.String()
 	}
+	for k := range r.directDeps {
+		s += " deps:" + k
+	}
 	if len(r.reason) != 0 {
 		s += " which is restricted because " + r.reason
 	}
@@ -368,6 +386,22 @@
 	return includePath && !excludePath
 }
 
+func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool {
+	if len(r.directDeps) == 0 {
+		return true
+	}
+
+	matches := false
+	ctx.VisitDirectDeps(func(m Module) {
+		if !matches {
+			name := ctx.OtherModuleName(m)
+			matches = r.directDeps[name]
+		}
+	})
+
+	return matches
+}
+
 func (r *rule) appliesToModuleType(moduleType string) bool {
 	return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
 }