summaryrefslogtreecommitdiff
path: root/android/visibility.go
diff options
context:
space:
mode:
Diffstat (limited to 'android/visibility.go')
-rw-r--r--android/visibility.go174
1 files changed, 128 insertions, 46 deletions
diff --git a/android/visibility.go b/android/visibility.go
index 36b6f35f8..c7ef1dae6 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -71,7 +71,17 @@ type visibilityRule interface {
String() string
}
-// A compositeRule is a visibility rule composed from other visibility rules.
+// A compositeRule is a visibility rule composed from a list of atomic visibility rules.
+//
+// The list corresponds to the list of strings in the visibility property after defaults expansion.
+// Even though //visibility:public is not allowed together with other rules in the visibility list
+// of a single module, it is allowed here to permit a module to override an inherited visibility
+// spec with public visibility.
+//
+// //visibility:private is not allowed in the same way, since we'd need to check for it during the
+// defaults expansion to make that work. No non-private visibility rules are allowed in a
+// compositeRule containing a privateRule.
+//
// This array will only be [] if all the rules are invalid and will behave as if visibility was
// ["//visibility:private"].
type compositeRule []visibilityRule
@@ -126,6 +136,28 @@ func (r subpackagesRule) String() string {
return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
}
+// visibilityRule for //visibility:public
+type publicRule struct{}
+
+func (r publicRule) matches(_ qualifiedModuleName) bool {
+ return true
+}
+
+func (r publicRule) String() string {
+ return "//visibility:public"
+}
+
+// visibilityRule for //visibility:private
+type privateRule struct{}
+
+func (r privateRule) matches(_ qualifiedModuleName) bool {
+ return false
+}
+
+func (r privateRule) String() string {
+ return "//visibility:private"
+}
+
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
// The map from qualifiedModuleName to visibilityRule.
@@ -135,8 +167,15 @@ func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
}).(*sync.Map)
}
+// The rule checker needs to be registered before defaults expansion to correctly check that
+// //visibility:xxx isn't combined with other packages in the same list in any one module.
+func registerVisibilityRuleChecker(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
+}
+
// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
-// having to process multiple variants for each module.
+// having to process multiple variants for each module. This goes after defaults expansion to gather
+// the complete visibility lists from flat lists.
func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
}
@@ -146,39 +185,35 @@ func registerVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
}
-// Gathers the visibility rules, parses the visibility properties, stores them in a map by
-// qualifiedModuleName for retrieval during enforcement.
-//
-// See ../README.md#Visibility for information on the format of the visibility rules.
-
-func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
- m, ok := ctx.Module().(Module)
- if !ok {
- return
- }
-
+// Checks the per-module visibility rule lists before defaults expansion.
+func visibilityRuleChecker(ctx BottomUpMutatorContext) {
qualified := createQualifiedModuleName(ctx)
-
- visibility := m.base().commonProperties.Visibility
- if visibility != nil {
- rule := parseRules(ctx, qualified.pkg, visibility)
- if rule != nil {
- moduleToVisibilityRuleMap(ctx).Store(qualified, rule)
+ if d, ok := ctx.Module().(Defaults); ok {
+ // Defaults modules don't store the payload properties in m.base().
+ for _, props := range d.properties() {
+ if cp, ok := props.(*commonProperties); ok {
+ if visibility := cp.Visibility; visibility != nil {
+ checkRules(ctx, qualified.pkg, visibility)
+ }
+ }
+ }
+ } else if m, ok := ctx.Module().(Module); ok {
+ if visibility := m.base().commonProperties.Visibility; visibility != nil {
+ checkRules(ctx, qualified.pkg, visibility)
}
}
}
-func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
+func checkRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) {
ruleCount := len(visibility)
if ruleCount == 0 {
// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
// it could mean public visibility. Requiring at least one rule makes the owner's intent
// clearer.
ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
- return nil
+ return
}
- rules := make(compositeRule, 0, ruleCount)
for _, v := range visibility {
ok, pkg, name := splitRule(ctx, v, currentPkg)
if !ok {
@@ -192,23 +227,19 @@ func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []stri
}
if pkg == "visibility" {
- if ruleCount != 1 {
- ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
- continue
- }
switch name {
- case "private":
- rules = append(rules, packageRule{currentPkg})
- continue
- case "public":
- return nil
+ case "private", "public":
case "legacy_public":
ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
- return nil
+ continue
default:
ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
continue
}
+ if ruleCount != 1 {
+ ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
+ continue
+ }
}
// If the current directory is not in the vendor tree then there are some additional
@@ -221,22 +252,76 @@ func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []stri
continue
}
}
+ }
+}
- // Create the rule
- var r visibilityRule
- switch name {
- case "__pkg__":
- r = packageRule{pkg}
- case "__subpackages__":
- r = subpackagesRule{pkg}
- default:
- ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
+// Gathers the flattened visibility rules after defaults expansion, parses the visibility
+// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement.
+//
+// See ../README.md#Visibility for information on the format of the visibility rules.
+func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
+ m, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+
+ qualified := createQualifiedModuleName(ctx)
+
+ visibility := m.base().commonProperties.Visibility
+ if visibility != nil {
+ rule := parseRules(ctx, qualified.pkg, visibility)
+ if rule != nil {
+ moduleToVisibilityRuleMap(ctx).Store(qualified, rule)
+ }
+ }
+}
+
+func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
+ rules := make(compositeRule, 0, len(visibility))
+ hasPrivateRule := false
+ hasNonPrivateRule := false
+ for _, v := range visibility {
+ ok, pkg, name := splitRule(ctx, v, currentPkg)
+ if !ok {
continue
}
+ var r visibilityRule
+ isPrivateRule := false
+ if pkg == "visibility" {
+ switch name {
+ case "private":
+ r = privateRule{}
+ isPrivateRule = true
+ case "public":
+ r = publicRule{}
+ }
+ } else {
+ switch name {
+ case "__pkg__":
+ r = packageRule{pkg}
+ case "__subpackages__":
+ r = subpackagesRule{pkg}
+ default:
+ continue
+ }
+ }
+
+ if isPrivateRule {
+ hasPrivateRule = true
+ } else {
+ hasNonPrivateRule = true
+ }
+
rules = append(rules, r)
}
+ if hasPrivateRule && hasNonPrivateRule {
+ ctx.PropertyErrorf("visibility",
+ "cannot mix \"//visibility:private\" with any other visibility rules")
+ return compositeRule{privateRule{}}
+ }
+
return rules
}
@@ -274,8 +359,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg string)
}
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
- _, ok := ctx.Module().(Module)
- if !ok {
+ if _, ok := ctx.Module().(Module); !ok {
return
}
@@ -297,9 +381,7 @@ func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
rule, ok := moduleToVisibilityRule.Load(depQualified)
if ok {
if !rule.(compositeRule).matches(qualified) {
- ctx.ModuleErrorf(
- "depends on %s which is not visible to this module; %s is only visible to %s",
- depQualified, depQualified, rule)
+ ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
}
}
})