2019-03-28 22:10:57 +08:00
|
|
|
// Copyright 2019 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package android
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2020-01-14 20:42:08 +08:00
|
|
|
|
|
|
|
"github.com/google/blueprint"
|
2019-03-28 22:10:57 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Enforces visibility rules between modules.
|
|
|
|
//
|
2019-05-31 21:00:04 +08:00
|
|
|
// Multi stage process:
|
|
|
|
// * First stage works bottom up, before defaults expansion, to check the syntax of the visibility
|
|
|
|
// rules that have been specified.
|
|
|
|
//
|
|
|
|
// * Second stage works bottom up to extract the package info for each package and store them in a
|
|
|
|
// map by package name. See package.go for functionality for this.
|
|
|
|
//
|
|
|
|
// * Third stage works bottom up to extract visibility information from the modules, parse it,
|
2019-03-28 22:10:57 +08:00
|
|
|
// create visibilityRule structures and store them in a map keyed by the module's
|
|
|
|
// qualifiedModuleName instance, i.e. //<pkg>:<name>. The map is stored in the context rather
|
|
|
|
// than a global variable for testing. Each test has its own Config so they do not share a map
|
2019-05-31 21:00:04 +08:00
|
|
|
// and so can be run in parallel. If a module has no visibility specified then it uses the
|
|
|
|
// default package visibility if specified.
|
2019-03-28 22:10:57 +08:00
|
|
|
//
|
2019-05-31 21:00:04 +08:00
|
|
|
// * Fourth stage works top down and iterates over all the deps for each module. If the dep is in
|
2019-03-28 22:10:57 +08:00
|
|
|
// the same package then it is automatically visible. Otherwise, for each dep it first extracts
|
|
|
|
// its visibilityRule from the config map. If one could not be found then it assumes that it is
|
|
|
|
// publicly visible. Otherwise, it calls the visibility rule to check that the module can see
|
|
|
|
// the dependency. If it cannot then an error is reported.
|
|
|
|
//
|
|
|
|
// TODO(b/130631145) - Make visibility work properly with prebuilts.
|
|
|
|
// TODO(b/130796911) - Make visibility work properly with defaults.
|
|
|
|
|
|
|
|
// Patterns for the values that can be specified in visibility property.
|
|
|
|
const (
|
|
|
|
packagePattern = `//([^/:]+(?:/[^/:]+)*)`
|
|
|
|
namePattern = `:([^/:]+)`
|
|
|
|
visibilityRulePattern = `^(?:` + packagePattern + `)?(?:` + namePattern + `)?$`
|
|
|
|
)
|
|
|
|
|
|
|
|
var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
|
|
|
|
|
|
|
|
// A visibility rule is associated with a module and determines which other modules it is visible
|
|
|
|
// to, i.e. which other modules can depend on the rule's module.
|
|
|
|
type visibilityRule interface {
|
|
|
|
// Check to see whether this rules matches m.
|
|
|
|
// Returns true if it does, false otherwise.
|
|
|
|
matches(m qualifiedModuleName) bool
|
|
|
|
|
|
|
|
String() string
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:00:04 +08:00
|
|
|
// Describes the properties provided by a module that contain visibility rules.
|
|
|
|
type visibilityPropertyImpl struct {
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
name string
|
|
|
|
stringsProperty *[]string
|
2019-05-31 21:00:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type visibilityProperty interface {
|
|
|
|
getName() string
|
|
|
|
getStrings() []string
|
|
|
|
}
|
|
|
|
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty {
|
2019-05-31 21:00:04 +08:00
|
|
|
return visibilityPropertyImpl{
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
name: name,
|
|
|
|
stringsProperty: stringsProperty,
|
2019-05-31 21:00:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p visibilityPropertyImpl) getName() string {
|
|
|
|
return p.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p visibilityPropertyImpl) getStrings() []string {
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
return *p.stringsProperty
|
2019-05-31 21:00:04 +08:00
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
// 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.
|
|
|
|
//
|
2019-03-28 22:10:57 +08:00
|
|
|
// This array will only be [] if all the rules are invalid and will behave as if visibility was
|
|
|
|
// ["//visibility:private"].
|
|
|
|
type compositeRule []visibilityRule
|
|
|
|
|
|
|
|
// A compositeRule matches if and only if any of its rules matches.
|
|
|
|
func (c compositeRule) matches(m qualifiedModuleName) bool {
|
|
|
|
for _, r := range c {
|
|
|
|
if r.matches(m) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:00:04 +08:00
|
|
|
func (c compositeRule) String() string {
|
2019-12-05 22:31:48 +08:00
|
|
|
return "[" + strings.Join(c.Strings(), ", ") + "]"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c compositeRule) Strings() []string {
|
2019-05-31 21:00:04 +08:00
|
|
|
s := make([]string, 0, len(c))
|
|
|
|
for _, r := range c {
|
2019-03-28 22:10:57 +08:00
|
|
|
s = append(s, r.String())
|
|
|
|
}
|
2019-12-05 22:31:48 +08:00
|
|
|
return s
|
2019-03-28 22:10:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory).
|
|
|
|
type packageRule struct {
|
|
|
|
pkg string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r packageRule) matches(m qualifiedModuleName) bool {
|
|
|
|
return m.pkg == r.pkg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r packageRule) String() string {
|
2020-05-13 08:54:21 +08:00
|
|
|
return fmt.Sprintf("//%s", r.pkg) // :__pkg__ is the default, so skip it.
|
2019-03-28 22:10:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// A subpackagesRule is a visibility rule that matches modules in a specific package (i.e.
|
|
|
|
// directory) or any of its subpackages (i.e. subdirectories).
|
|
|
|
type subpackagesRule struct {
|
|
|
|
pkgPrefix string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r subpackagesRule) matches(m qualifiedModuleName) bool {
|
|
|
|
return isAncestor(r.pkgPrefix, m.pkg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func isAncestor(p1 string, p2 string) bool {
|
|
|
|
return strings.HasPrefix(p2+"/", p1+"/")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r subpackagesRule) String() string {
|
|
|
|
return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
|
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
// 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"
|
|
|
|
}
|
|
|
|
|
2019-03-28 22:10:57 +08:00
|
|
|
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
|
|
|
|
|
|
|
|
// The map from qualifiedModuleName to visibilityRule.
|
2020-02-20 00:10:09 +08:00
|
|
|
func moduleToVisibilityRuleMap(config Config) *sync.Map {
|
|
|
|
return config.Once(visibilityRuleMap, func() interface{} {
|
2019-03-28 22:10:57 +08:00
|
|
|
return &sync.Map{}
|
|
|
|
}).(*sync.Map)
|
|
|
|
}
|
|
|
|
|
2020-01-14 20:42:08 +08:00
|
|
|
// Marker interface that identifies dependencies that are excluded from visibility
|
|
|
|
// enforcement.
|
|
|
|
type ExcludeFromVisibilityEnforcementTag interface {
|
|
|
|
blueprint.DependencyTag
|
|
|
|
|
|
|
|
// Method that differentiates this interface from others.
|
|
|
|
ExcludeFromVisibilityEnforcement()
|
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
// 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.
|
2019-12-05 22:31:48 +08:00
|
|
|
func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
|
2019-05-18 05:42:02 +08:00
|
|
|
ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:00:04 +08:00
|
|
|
// Registers the function that gathers the visibility rules for each module.
|
|
|
|
//
|
2019-03-28 22:10:57 +08:00
|
|
|
// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
|
2019-05-18 05:42:02 +08:00
|
|
|
// having to process multiple variants for each module. This goes after defaults expansion to gather
|
2019-05-31 21:00:04 +08:00
|
|
|
// the complete visibility lists from flat lists and after the package info is gathered to ensure
|
|
|
|
// that default_visibility is available.
|
2019-12-05 22:31:48 +08:00
|
|
|
func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
|
2019-03-28 22:10:57 +08:00
|
|
|
ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
|
|
|
|
}
|
|
|
|
|
|
|
|
// This must be registered after the deps have been resolved.
|
2019-12-05 22:31:48 +08:00
|
|
|
func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
|
2019-03-28 22:10:57 +08:00
|
|
|
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
|
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
// Checks the per-module visibility rule lists before defaults expansion.
|
|
|
|
func visibilityRuleChecker(ctx BottomUpMutatorContext) {
|
2019-03-28 22:10:57 +08:00
|
|
|
qualified := createQualifiedModuleName(ctx)
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
if m, ok := ctx.Module().(Module); ok {
|
2019-05-31 21:00:04 +08:00
|
|
|
visibilityProperties := m.visibilityProperties()
|
|
|
|
for _, p := range visibilityProperties {
|
|
|
|
if visibility := p.getStrings(); visibility != nil {
|
|
|
|
checkRules(ctx, qualified.pkg, p.getName(), visibility)
|
|
|
|
}
|
2019-03-28 22:10:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:00:04 +08:00
|
|
|
func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) {
|
2019-03-28 22:10:57 +08:00
|
|
|
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.
|
2019-05-31 21:00:04 +08:00
|
|
|
ctx.PropertyErrorf(property, "must contain at least one visibility rule")
|
2019-05-18 05:42:02 +08:00
|
|
|
return
|
2019-03-28 22:10:57 +08:00
|
|
|
}
|
|
|
|
|
2020-05-06 02:19:22 +08:00
|
|
|
for i, v := range visibility {
|
2020-05-02 01:13:36 +08:00
|
|
|
ok, pkg, name := splitRule(ctx, v, currentPkg, property)
|
2019-03-28 22:10:57 +08:00
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if pkg == "visibility" {
|
|
|
|
switch name {
|
2019-05-18 05:42:02 +08:00
|
|
|
case "private", "public":
|
2019-03-28 22:10:57 +08:00
|
|
|
case "legacy_public":
|
2019-05-31 21:00:04 +08:00
|
|
|
ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
|
2019-05-18 05:42:02 +08:00
|
|
|
continue
|
2020-05-06 02:19:22 +08:00
|
|
|
case "override":
|
|
|
|
// This keyword does not create a rule so pretend it does not exist.
|
|
|
|
ruleCount -= 1
|
2019-03-28 22:10:57 +08:00
|
|
|
default:
|
2019-05-31 21:00:04 +08:00
|
|
|
ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
|
2019-03-28 22:10:57 +08:00
|
|
|
continue
|
|
|
|
}
|
2020-05-06 02:19:22 +08:00
|
|
|
if name == "override" {
|
|
|
|
if i != 0 {
|
|
|
|
ctx.PropertyErrorf(property, `"%v" may only be used at the start of the visibility rules`, v)
|
|
|
|
}
|
|
|
|
} else if ruleCount != 1 {
|
2019-05-31 21:00:04 +08:00
|
|
|
ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v)
|
2019-05-18 05:42:02 +08:00
|
|
|
continue
|
|
|
|
}
|
2019-03-28 22:10:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the current directory is not in the vendor tree then there are some additional
|
|
|
|
// restrictions on the rules.
|
|
|
|
if !isAncestor("vendor", currentPkg) {
|
|
|
|
if !isAllowedFromOutsideVendor(pkg, name) {
|
2019-05-31 21:00:04 +08:00
|
|
|
ctx.PropertyErrorf(property,
|
2019-03-28 22:10:57 +08:00
|
|
|
"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
|
|
|
|
" targets within //vendor, they can only use //vendor:__subpackages__.", v)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2019-05-18 05:42:02 +08:00
|
|
|
}
|
|
|
|
}
|
2019-03-28 22:10:57 +08:00
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:00:04 +08:00
|
|
|
qualifiedModuleId := m.qualifiedModuleId(ctx)
|
|
|
|
currentPkg := qualifiedModuleId.pkg
|
2019-05-18 05:42:02 +08:00
|
|
|
|
Refactor visibility to support visibility on defaults modules
Existing modules, either general one or package ones have a single
visibility property, called visibility in general, and
default_visibility on package, that controls access to that module, or
in the case of package sets the default visibility of all modules in
that package. The property is checked and gathered during the similarly
named phases of visibility processing.
The defaults module will be different as it will have two properties.
The first, visibility, will not affect the visibility of the module, it
only affects the visibility of modules that 'extend' the defaults. So,
it will need checking but not parsing. The second property,
defaults_visibility, will affect the visibility of the module and so
will need both checking and parsing.
The current implementation does not handle those cases because:
1) It does not differentiate between the property that affects the
module and those that do not. It checks and gathers all of them with
the last property gathered overriding the rules for the previous
properties.
2) It relies on overriding methods in MethodBase in order to change the
default behavior for the package module. That works because
packageModule embeds ModuleBase but will not work for
DefaultsModuleBase as it does not embed ModuleBase and instead is
embedded alongside it so attempting to override a method in
MethodBase leads to ambiguity.
This change addresses the issues as follows:
1) It adds a new visibility() []string method to get access to the
primary visibility rules, i.e. the ones that affect the module.
2) It adds two fields, 'visibilityPropertyInfo []visibilityProperty'
to provide information about all the properties that need checking,
and 'primaryVisibilityProperty visibilityProperty' to specify the
property that affects the module.
The PackageFactory() and InitAndroidModule(Module) functions are
modified to initialize the fields. The override of the
visibilityProperties() method for packageModule is removed and the
default implementations of visibilityProperties() and visibility()
on ModuleBase return information from the two new fields.
The InitDefaultsModule is updated to also initialize the two new
fields. It uses nil for primaryVisibilityProperty for now but that
will be changed to return defaults_visibility. It also uses the
commonProperties structure created for the defaults directly instead
of having to search for it through properties().
Changed the visibilityProperty to take a pointer to the property that
can be used to retrieve the value rather than a lambda function.
Bug: 130796911
Test: m nothing
Change-Id: Icadd470a5f692a48ec61de02bf3dfde3e2eea2ef
2019-07-24 21:24:38 +08:00
|
|
|
// Parse the visibility rules that control access to the module and store them by id
|
|
|
|
// for use when enforcing the rules.
|
2020-05-02 01:13:36 +08:00
|
|
|
primaryProperty := m.base().primaryVisibilityProperty
|
|
|
|
if primaryProperty != nil {
|
|
|
|
if visibility := primaryProperty.getStrings(); visibility != nil {
|
|
|
|
rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
|
|
|
|
if rule != nil {
|
|
|
|
moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
|
|
|
|
}
|
2019-05-18 05:42:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 01:13:36 +08:00
|
|
|
func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
|
2019-05-18 05:42:02 +08:00
|
|
|
rules := make(compositeRule, 0, len(visibility))
|
|
|
|
hasPrivateRule := false
|
2020-02-20 00:10:09 +08:00
|
|
|
hasPublicRule := false
|
2019-05-18 05:42:02 +08:00
|
|
|
hasNonPrivateRule := false
|
|
|
|
for _, v := range visibility {
|
2020-05-02 01:13:36 +08:00
|
|
|
ok, pkg, name := splitRule(ctx, v, currentPkg, property)
|
2019-05-18 05:42:02 +08:00
|
|
|
if !ok {
|
2019-03-28 22:10:57 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
var r visibilityRule
|
|
|
|
isPrivateRule := false
|
|
|
|
if pkg == "visibility" {
|
|
|
|
switch name {
|
|
|
|
case "private":
|
|
|
|
r = privateRule{}
|
|
|
|
isPrivateRule = true
|
|
|
|
case "public":
|
|
|
|
r = publicRule{}
|
2020-02-20 00:10:09 +08:00
|
|
|
hasPublicRule = true
|
2020-05-06 02:19:22 +08:00
|
|
|
case "override":
|
|
|
|
// Discard all preceding rules and any state based on them.
|
|
|
|
rules = nil
|
|
|
|
hasPrivateRule = false
|
|
|
|
hasPublicRule = false
|
|
|
|
hasNonPrivateRule = false
|
|
|
|
// This does not actually create a rule so continue onto the next rule.
|
|
|
|
continue
|
2019-05-18 05:42:02 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch name {
|
|
|
|
case "__pkg__":
|
|
|
|
r = packageRule{pkg}
|
|
|
|
case "__subpackages__":
|
|
|
|
r = subpackagesRule{pkg}
|
|
|
|
default:
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if isPrivateRule {
|
|
|
|
hasPrivateRule = true
|
|
|
|
} else {
|
|
|
|
hasNonPrivateRule = true
|
|
|
|
}
|
|
|
|
|
2019-03-28 22:10:57 +08:00
|
|
|
rules = append(rules, r)
|
|
|
|
}
|
|
|
|
|
2019-05-18 05:42:02 +08:00
|
|
|
if hasPrivateRule && hasNonPrivateRule {
|
|
|
|
ctx.PropertyErrorf("visibility",
|
|
|
|
"cannot mix \"//visibility:private\" with any other visibility rules")
|
|
|
|
return compositeRule{privateRule{}}
|
|
|
|
}
|
|
|
|
|
2020-02-20 00:10:09 +08:00
|
|
|
if hasPublicRule {
|
|
|
|
// Public overrides all other rules so just return it.
|
|
|
|
return compositeRule{publicRule{}}
|
|
|
|
}
|
|
|
|
|
2019-03-28 22:10:57 +08:00
|
|
|
return rules
|
|
|
|
}
|
|
|
|
|
|
|
|
func isAllowedFromOutsideVendor(pkg string, name string) bool {
|
|
|
|
if pkg == "vendor" {
|
|
|
|
if name == "__subpackages__" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return !isAncestor("vendor", pkg)
|
|
|
|
}
|
|
|
|
|
2020-05-02 01:13:36 +08:00
|
|
|
func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) {
|
2019-03-28 22:10:57 +08:00
|
|
|
// Make sure that the rule is of the correct format.
|
|
|
|
matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
|
|
|
|
if ruleExpression == "" || matches == nil {
|
2020-05-02 01:13:36 +08:00
|
|
|
// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
|
|
|
|
// ensure all the rules on this module are checked.
|
|
|
|
ctx.PropertyErrorf(property,
|
|
|
|
"invalid visibility pattern %q must match"+
|
|
|
|
" //<package>:<module>, //<package> or :<module>",
|
|
|
|
ruleExpression)
|
2019-03-28 22:10:57 +08:00
|
|
|
return false, "", ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the package and name.
|
|
|
|
pkg := matches[1]
|
|
|
|
name := matches[2]
|
|
|
|
|
|
|
|
// Normalize the short hands
|
|
|
|
if pkg == "" {
|
|
|
|
pkg = currentPkg
|
|
|
|
}
|
|
|
|
if name == "" {
|
|
|
|
name = "__pkg__"
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, pkg, name
|
|
|
|
}
|
|
|
|
|
|
|
|
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
2019-05-18 05:42:02 +08:00
|
|
|
if _, ok := ctx.Module().(Module); !ok {
|
2019-03-28 22:10:57 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
qualified := createQualifiedModuleName(ctx)
|
|
|
|
|
|
|
|
// Visit all the dependencies making sure that this module has access to them all.
|
|
|
|
ctx.VisitDirectDeps(func(dep Module) {
|
2020-01-14 20:42:08 +08:00
|
|
|
// Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag
|
|
|
|
tag := ctx.OtherModuleDependencyTag(dep)
|
|
|
|
if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-03-28 22:10:57 +08:00
|
|
|
depName := ctx.OtherModuleName(dep)
|
|
|
|
depDir := ctx.OtherModuleDir(dep)
|
|
|
|
depQualified := qualifiedModuleName{depDir, depName}
|
|
|
|
|
|
|
|
// Targets are always visible to other targets in their own package.
|
|
|
|
if depQualified.pkg == qualified.pkg {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-20 00:10:09 +08:00
|
|
|
rule := effectiveVisibilityRules(ctx.Config(), depQualified)
|
2019-05-31 21:00:04 +08:00
|
|
|
if rule != nil && !rule.matches(qualified) {
|
|
|
|
ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
|
|
|
|
}
|
2019-03-28 22:10:57 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-20 00:10:09 +08:00
|
|
|
func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
|
|
|
|
moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
|
2019-12-05 22:31:48 +08:00
|
|
|
value, ok := moduleToVisibilityRule.Load(qualified)
|
|
|
|
var rule compositeRule
|
|
|
|
if ok {
|
|
|
|
rule = value.(compositeRule)
|
|
|
|
} else {
|
2020-02-20 00:10:09 +08:00
|
|
|
rule = packageDefaultVisibility(config, qualified)
|
2019-12-05 22:31:48 +08:00
|
|
|
}
|
|
|
|
return rule
|
|
|
|
}
|
|
|
|
|
2019-03-28 22:10:57 +08:00
|
|
|
func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName {
|
|
|
|
moduleName := ctx.ModuleName()
|
|
|
|
dir := ctx.ModuleDir()
|
|
|
|
qualified := qualifiedModuleName{dir, moduleName}
|
|
|
|
return qualified
|
|
|
|
}
|
2019-06-20 23:38:08 +08:00
|
|
|
|
2020-02-20 00:10:09 +08:00
|
|
|
func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
|
|
|
|
moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
|
2019-06-20 23:38:08 +08:00
|
|
|
packageQualifiedId := moduleId.getContainingPackageId()
|
|
|
|
for {
|
|
|
|
value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
|
|
|
|
if ok {
|
|
|
|
return value.(compositeRule)
|
|
|
|
}
|
|
|
|
|
|
|
|
if packageQualifiedId.isRootPackage() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
packageQualifiedId = packageQualifiedId.getContainingPackageId()
|
|
|
|
}
|
|
|
|
}
|
2019-12-05 22:31:48 +08:00
|
|
|
|
|
|
|
// Get the effective visibility rules, i.e. the actual rules that affect the visibility of the
|
|
|
|
// property irrespective of where they are defined.
|
|
|
|
//
|
|
|
|
// Includes visibility rules specified by package default_visibility and/or on defaults.
|
|
|
|
// Short hand forms, e.g. //:__subpackages__ are replaced with their full form, e.g.
|
|
|
|
// //package/containing/rule:__subpackages__.
|
|
|
|
func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) []string {
|
|
|
|
moduleName := ctx.OtherModuleName(module)
|
|
|
|
dir := ctx.OtherModuleDir(module)
|
|
|
|
qualified := qualifiedModuleName{dir, moduleName}
|
|
|
|
|
2020-02-20 00:10:09 +08:00
|
|
|
rule := effectiveVisibilityRules(ctx.Config(), qualified)
|
2019-12-05 22:31:48 +08:00
|
|
|
|
2020-05-13 09:20:06 +08:00
|
|
|
// Modules are implicitly visible to other modules in the same package,
|
|
|
|
// without checking the visibility rules. Here we need to add that visibility
|
|
|
|
// explicitly.
|
|
|
|
if rule != nil && !rule.matches(qualified) {
|
2020-05-14 05:11:40 +08:00
|
|
|
if len(rule) == 1 {
|
|
|
|
if _, ok := rule[0].(privateRule); ok {
|
|
|
|
// If the rule is //visibility:private we can't append another
|
|
|
|
// visibility to it. Semantically we need to convert it to a package
|
|
|
|
// visibility rule for the location where the result is used, but since
|
|
|
|
// modules are implicitly visible within the package we get the same
|
|
|
|
// result without any rule at all, so just make it an empty list to be
|
|
|
|
// appended below.
|
|
|
|
rule = compositeRule{}
|
|
|
|
}
|
|
|
|
}
|
2020-05-13 09:20:06 +08:00
|
|
|
rule = append(rule, packageRule{dir})
|
|
|
|
}
|
|
|
|
|
2019-12-05 22:31:48 +08:00
|
|
|
return rule.Strings()
|
|
|
|
}
|
2020-05-02 00:52:01 +08:00
|
|
|
|
|
|
|
// Clear the default visibility properties so they can be replaced.
|
|
|
|
func clearVisibilityProperties(module Module) {
|
|
|
|
module.base().visibilityPropertyInfo = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a property that contains visibility rules so that they are checked for
|
|
|
|
// correctness.
|
|
|
|
func AddVisibilityProperty(module Module, name string, stringsProperty *[]string) {
|
|
|
|
addVisibilityProperty(module, name, stringsProperty)
|
|
|
|
}
|
|
|
|
|
|
|
|
func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty {
|
|
|
|
base := module.base()
|
|
|
|
property := newVisibilityProperty(name, stringsProperty)
|
|
|
|
base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property)
|
|
|
|
return property
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the primary visibility property.
|
|
|
|
//
|
|
|
|
// Also adds the property to the list of properties to be validated.
|
|
|
|
func setPrimaryVisibilityProperty(module Module, name string, stringsProperty *[]string) {
|
|
|
|
module.base().primaryVisibilityProperty = addVisibilityProperty(module, name, stringsProperty)
|
|
|
|
}
|