xref: /aosp_15_r20/external/bazel-skylib/gazelle/bzl/gazelle.go (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1*bcb5dc79SHONG Yifan/* Copyright 2020 The Bazel Authors. All rights reserved.
2*bcb5dc79SHONG Yifan
3*bcb5dc79SHONG YifanLicensed under the Apache License, Version 2.0 (the "License");
4*bcb5dc79SHONG Yifanyou may not use this file except in compliance with the License.
5*bcb5dc79SHONG YifanYou may obtain a copy of the License at
6*bcb5dc79SHONG Yifan
7*bcb5dc79SHONG Yifan   http://www.apache.org/licenses/LICENSE-2.0
8*bcb5dc79SHONG Yifan
9*bcb5dc79SHONG YifanUnless required by applicable law or agreed to in writing, software
10*bcb5dc79SHONG Yifandistributed under the License is distributed on an "AS IS" BASIS,
11*bcb5dc79SHONG YifanWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*bcb5dc79SHONG YifanSee the License for the specific language governing permissions and
13*bcb5dc79SHONG Yifanlimitations under the License.
14*bcb5dc79SHONG Yifan*/
15*bcb5dc79SHONG Yifan
16*bcb5dc79SHONG Yifan// Package bzl generates a `bzl_library` target for every `.bzl` file in
17*bcb5dc79SHONG Yifan// each package.
18*bcb5dc79SHONG Yifan//
19*bcb5dc79SHONG Yifan// The `bzl_library` rule is provided by
20*bcb5dc79SHONG Yifan// https://github.com/bazelbuild/bazel-skylib.
21*bcb5dc79SHONG Yifan//
22*bcb5dc79SHONG Yifan// This extension is experimental and subject to change. It is not included
23*bcb5dc79SHONG Yifan// in the default Gazelle binary.
24*bcb5dc79SHONG Yifanpackage bzl
25*bcb5dc79SHONG Yifan
26*bcb5dc79SHONG Yifanimport (
27*bcb5dc79SHONG Yifan	"flag"
28*bcb5dc79SHONG Yifan	"fmt"
29*bcb5dc79SHONG Yifan	"io/ioutil"
30*bcb5dc79SHONG Yifan	"log"
31*bcb5dc79SHONG Yifan	"path/filepath"
32*bcb5dc79SHONG Yifan	"sort"
33*bcb5dc79SHONG Yifan	"strings"
34*bcb5dc79SHONG Yifan
35*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/config"
36*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/label"
37*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/language"
38*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/pathtools"
39*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/repo"
40*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/resolve"
41*bcb5dc79SHONG Yifan	"github.com/bazelbuild/bazel-gazelle/rule"
42*bcb5dc79SHONG Yifan
43*bcb5dc79SHONG Yifan	"github.com/bazelbuild/buildtools/build"
44*bcb5dc79SHONG Yifan)
45*bcb5dc79SHONG Yifan
46*bcb5dc79SHONG Yifanconst languageName = "starlark"
47*bcb5dc79SHONG Yifanconst fileType = ".bzl"
48*bcb5dc79SHONG Yifan
49*bcb5dc79SHONG Yifanvar ignoreSuffix = suffixes{
50*bcb5dc79SHONG Yifan	"_tests.bzl",
51*bcb5dc79SHONG Yifan	"_test.bzl",
52*bcb5dc79SHONG Yifan}
53*bcb5dc79SHONG Yifan
54*bcb5dc79SHONG Yifantype suffixes []string
55*bcb5dc79SHONG Yifan
56*bcb5dc79SHONG Yifanfunc (s suffixes) Matches(test string) bool {
57*bcb5dc79SHONG Yifan	for _, v := range s {
58*bcb5dc79SHONG Yifan		if strings.HasSuffix(test, v) {
59*bcb5dc79SHONG Yifan			return true
60*bcb5dc79SHONG Yifan		}
61*bcb5dc79SHONG Yifan	}
62*bcb5dc79SHONG Yifan	return false
63*bcb5dc79SHONG Yifan}
64*bcb5dc79SHONG Yifan
65*bcb5dc79SHONG Yifantype bzlLibraryLang struct{}
66*bcb5dc79SHONG Yifan
67*bcb5dc79SHONG Yifan// NewLanguage is called by Gazelle to install this language extension in a binary.
68*bcb5dc79SHONG Yifanfunc NewLanguage() language.Language {
69*bcb5dc79SHONG Yifan	return &bzlLibraryLang{}
70*bcb5dc79SHONG Yifan}
71*bcb5dc79SHONG Yifan
72*bcb5dc79SHONG Yifan// Name returns the name of the language. This should be a prefix of the
73*bcb5dc79SHONG Yifan// kinds of rules generated by the language, e.g., "go" for the Go extension
74*bcb5dc79SHONG Yifan// since it generates "go_library" rules.
75*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Name() string { return languageName }
76*bcb5dc79SHONG Yifan
77*bcb5dc79SHONG Yifan// The following methods are implemented to satisfy the
78*bcb5dc79SHONG Yifan// https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/resolve?tab=doc#Resolver
79*bcb5dc79SHONG Yifan// interface, but are otherwise unused.
80*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {}
81*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) CheckFlags(fs *flag.FlagSet, c *config.Config) error          { return nil }
82*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) KnownDirectives() []string                                    { return nil }
83*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Configure(c *config.Config, rel string, f *rule.File)         {}
84*bcb5dc79SHONG Yifan
85*bcb5dc79SHONG Yifan// Kinds returns a map of maps rule names (kinds) and information on how to
86*bcb5dc79SHONG Yifan// match and merge attributes that may be found in rules of those kinds. All
87*bcb5dc79SHONG Yifan// kinds of rules generated for this language may be found here.
88*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Kinds() map[string]rule.KindInfo {
89*bcb5dc79SHONG Yifan	return kinds
90*bcb5dc79SHONG Yifan}
91*bcb5dc79SHONG Yifan
92*bcb5dc79SHONG Yifan// Loads returns .bzl files and symbols they define. Every rule generated by
93*bcb5dc79SHONG Yifan// GenerateRules, now or in the past, should be loadable from one of these
94*bcb5dc79SHONG Yifan// files.
95*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Loads() []rule.LoadInfo {
96*bcb5dc79SHONG Yifan	return []rule.LoadInfo{{
97*bcb5dc79SHONG Yifan		Name:    "@bazel_skylib//:bzl_library.bzl",
98*bcb5dc79SHONG Yifan		Symbols: []string{"bzl_library"},
99*bcb5dc79SHONG Yifan	}}
100*bcb5dc79SHONG Yifan}
101*bcb5dc79SHONG Yifan
102*bcb5dc79SHONG Yifan// Fix repairs deprecated usage of language-specific rules in f. This is
103*bcb5dc79SHONG Yifan// called before the file is indexed. Unless c.ShouldFix is true, fixes
104*bcb5dc79SHONG Yifan// that delete or rename rules should not be performed.
105*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Fix(c *config.Config, f *rule.File) {}
106*bcb5dc79SHONG Yifan
107*bcb5dc79SHONG Yifan// Imports returns a list of ImportSpecs that can be used to import the rule
108*bcb5dc79SHONG Yifan// r. This is used to populate RuleIndex.
109*bcb5dc79SHONG Yifan//
110*bcb5dc79SHONG Yifan// If nil is returned, the rule will not be indexed. If any non-nil slice is
111*bcb5dc79SHONG Yifan// returned, including an empty slice, the rule will be indexed.
112*bcb5dc79SHONG Yifanfunc (b *bzlLibraryLang) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec {
113*bcb5dc79SHONG Yifan	srcs := r.AttrStrings("srcs")
114*bcb5dc79SHONG Yifan	imports := make([]resolve.ImportSpec, 0, len(srcs))
115*bcb5dc79SHONG Yifan
116*bcb5dc79SHONG Yifan	for _, src := range srcs {
117*bcb5dc79SHONG Yifan		spec := resolve.ImportSpec{
118*bcb5dc79SHONG Yifan			// Lang is the language in which the import string appears (this should
119*bcb5dc79SHONG Yifan			// match Resolver.Name).
120*bcb5dc79SHONG Yifan			Lang: languageName,
121*bcb5dc79SHONG Yifan			// Imp is an import string for the library.
122*bcb5dc79SHONG Yifan			Imp: fmt.Sprintf("//%s:%s", f.Pkg, src),
123*bcb5dc79SHONG Yifan		}
124*bcb5dc79SHONG Yifan
125*bcb5dc79SHONG Yifan		imports = append(imports, spec)
126*bcb5dc79SHONG Yifan	}
127*bcb5dc79SHONG Yifan
128*bcb5dc79SHONG Yifan	return imports
129*bcb5dc79SHONG Yifan}
130*bcb5dc79SHONG Yifan
131*bcb5dc79SHONG Yifan// Embeds returns a list of labels of rules that the given rule embeds. If
132*bcb5dc79SHONG Yifan// a rule is embedded by another importable rule of the same language, only
133*bcb5dc79SHONG Yifan// the embedding rule will be indexed. The embedding rule will inherit
134*bcb5dc79SHONG Yifan// the imports of the embedded rule.
135*bcb5dc79SHONG Yifan// Since SkyLark doesn't support embedding this should always return nil.
136*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Embeds(r *rule.Rule, from label.Label) []label.Label { return nil }
137*bcb5dc79SHONG Yifan
138*bcb5dc79SHONG Yifan// Resolve translates imported libraries for a given rule into Bazel
139*bcb5dc79SHONG Yifan// dependencies. Information about imported libraries is returned for each
140*bcb5dc79SHONG Yifan// rule generated by language.GenerateRules in
141*bcb5dc79SHONG Yifan// language.GenerateResult.Imports. Resolve generates a "deps" attribute (or
142*bcb5dc79SHONG Yifan// the appropriate language-specific equivalent) for each import according to
143*bcb5dc79SHONG Yifan// language-specific rules and heuristics.
144*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, r *rule.Rule, importsRaw interface{}, from label.Label) {
145*bcb5dc79SHONG Yifan	imports := importsRaw.([]string)
146*bcb5dc79SHONG Yifan
147*bcb5dc79SHONG Yifan	r.DelAttr("deps")
148*bcb5dc79SHONG Yifan
149*bcb5dc79SHONG Yifan	if len(imports) == 0 {
150*bcb5dc79SHONG Yifan		return
151*bcb5dc79SHONG Yifan	}
152*bcb5dc79SHONG Yifan
153*bcb5dc79SHONG Yifan	deps := make([]string, 0, len(imports))
154*bcb5dc79SHONG Yifan	for _, imp := range imports {
155*bcb5dc79SHONG Yifan		impLabel, err := label.Parse(imp)
156*bcb5dc79SHONG Yifan		if err != nil {
157*bcb5dc79SHONG Yifan			log.Printf("%s: import of %q is invalid: %v", from.String(), imp, err)
158*bcb5dc79SHONG Yifan			continue
159*bcb5dc79SHONG Yifan		}
160*bcb5dc79SHONG Yifan
161*bcb5dc79SHONG Yifan		// the index only contains absolute labels, not relative
162*bcb5dc79SHONG Yifan		impLabel = impLabel.Abs(from.Repo, from.Pkg)
163*bcb5dc79SHONG Yifan
164*bcb5dc79SHONG Yifan		if impLabel.Repo == "bazel_tools" {
165*bcb5dc79SHONG Yifan			// The @bazel_tools repo is tricky because it is a part of the "shipped
166*bcb5dc79SHONG Yifan			// with bazel" core library for interacting with the outside world.
167*bcb5dc79SHONG Yifan			// This means that it can not depend on skylib. Fortunately there is a
168*bcb5dc79SHONG Yifan			// fairly simple workaround for this, which is that you can add those
169*bcb5dc79SHONG Yifan			// bzl files as `deps` entries.
170*bcb5dc79SHONG Yifan			deps = append(deps, imp)
171*bcb5dc79SHONG Yifan			continue
172*bcb5dc79SHONG Yifan		}
173*bcb5dc79SHONG Yifan
174*bcb5dc79SHONG Yifan		if impLabel.Repo != "" || !c.IndexLibraries {
175*bcb5dc79SHONG Yifan			// This is a dependency that is external to the current repo, or indexing
176*bcb5dc79SHONG Yifan			// is disabled so take a guess at what the target name should be.
177*bcb5dc79SHONG Yifan			deps = append(deps, strings.TrimSuffix(imp, fileType))
178*bcb5dc79SHONG Yifan			continue
179*bcb5dc79SHONG Yifan		}
180*bcb5dc79SHONG Yifan
181*bcb5dc79SHONG Yifan		res := resolve.ImportSpec{
182*bcb5dc79SHONG Yifan			Lang: languageName,
183*bcb5dc79SHONG Yifan			Imp:  impLabel.String(),
184*bcb5dc79SHONG Yifan		}
185*bcb5dc79SHONG Yifan		matches := ix.FindRulesByImport(res, languageName)
186*bcb5dc79SHONG Yifan
187*bcb5dc79SHONG Yifan		if len(matches) == 0 {
188*bcb5dc79SHONG Yifan			log.Printf("%s: %q (%s) was not found in dependency index. Skipping. This may result in an incomplete deps section and require manual BUILD file intervention.\n", from.String(), imp, impLabel.String())
189*bcb5dc79SHONG Yifan		}
190*bcb5dc79SHONG Yifan
191*bcb5dc79SHONG Yifan		for _, m := range matches {
192*bcb5dc79SHONG Yifan			depLabel := m.Label
193*bcb5dc79SHONG Yifan			depLabel = depLabel.Rel(from.Repo, from.Pkg)
194*bcb5dc79SHONG Yifan			deps = append(deps, depLabel.String())
195*bcb5dc79SHONG Yifan		}
196*bcb5dc79SHONG Yifan	}
197*bcb5dc79SHONG Yifan
198*bcb5dc79SHONG Yifan	sort.Strings(deps)
199*bcb5dc79SHONG Yifan	if len(deps) > 0 {
200*bcb5dc79SHONG Yifan		r.SetAttr("deps", deps)
201*bcb5dc79SHONG Yifan	}
202*bcb5dc79SHONG Yifan}
203*bcb5dc79SHONG Yifan
204*bcb5dc79SHONG Yifanvar kinds = map[string]rule.KindInfo{
205*bcb5dc79SHONG Yifan	"bzl_library": {
206*bcb5dc79SHONG Yifan		NonEmptyAttrs:  map[string]bool{"srcs": true, "deps": true},
207*bcb5dc79SHONG Yifan		MergeableAttrs: map[string]bool{"srcs": true},
208*bcb5dc79SHONG Yifan	},
209*bcb5dc79SHONG Yifan}
210*bcb5dc79SHONG Yifan
211*bcb5dc79SHONG Yifan// GenerateRules extracts build metadata from source files in a directory.
212*bcb5dc79SHONG Yifan// GenerateRules is called in each directory where an update is requested
213*bcb5dc79SHONG Yifan// in depth-first post-order.
214*bcb5dc79SHONG Yifan//
215*bcb5dc79SHONG Yifan// args contains the arguments for GenerateRules. This is passed as a
216*bcb5dc79SHONG Yifan// struct to avoid breaking implementations in the future when new
217*bcb5dc79SHONG Yifan// fields are added.
218*bcb5dc79SHONG Yifan//
219*bcb5dc79SHONG Yifan// A GenerateResult struct is returned. Optional fields may be added to this
220*bcb5dc79SHONG Yifan// type in the future.
221*bcb5dc79SHONG Yifan//
222*bcb5dc79SHONG Yifan// Any non-fatal errors this function encounters should be logged using
223*bcb5dc79SHONG Yifan// log.Print.
224*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.GenerateResult {
225*bcb5dc79SHONG Yifan	var rules []*rule.Rule
226*bcb5dc79SHONG Yifan	var imports []interface{}
227*bcb5dc79SHONG Yifan	for _, f := range append(args.RegularFiles, args.GenFiles...) {
228*bcb5dc79SHONG Yifan		if !isBzlSourceFile(f) {
229*bcb5dc79SHONG Yifan			continue
230*bcb5dc79SHONG Yifan		}
231*bcb5dc79SHONG Yifan		name := strings.TrimSuffix(f, fileType)
232*bcb5dc79SHONG Yifan		r := rule.NewRule("bzl_library", name)
233*bcb5dc79SHONG Yifan
234*bcb5dc79SHONG Yifan		r.SetAttr("srcs", []string{f})
235*bcb5dc79SHONG Yifan
236*bcb5dc79SHONG Yifan		shouldSetVisibility := args.File == nil || !args.File.HasDefaultVisibility()
237*bcb5dc79SHONG Yifan		if shouldSetVisibility {
238*bcb5dc79SHONG Yifan			vis := checkInternalVisibility(args.Rel, "//visibility:public")
239*bcb5dc79SHONG Yifan			r.SetAttr("visibility", []string{vis})
240*bcb5dc79SHONG Yifan		}
241*bcb5dc79SHONG Yifan
242*bcb5dc79SHONG Yifan		fullPath := filepath.Join(args.Dir, f)
243*bcb5dc79SHONG Yifan		loads, err := getBzlFileLoads(fullPath)
244*bcb5dc79SHONG Yifan		if err != nil {
245*bcb5dc79SHONG Yifan			log.Printf("%s: contains syntax errors: %v", fullPath, err)
246*bcb5dc79SHONG Yifan			// Don't `continue` since it is reasonable to create a target even
247*bcb5dc79SHONG Yifan			// without deps.
248*bcb5dc79SHONG Yifan		}
249*bcb5dc79SHONG Yifan
250*bcb5dc79SHONG Yifan		rules = append(rules, r)
251*bcb5dc79SHONG Yifan		imports = append(imports, loads)
252*bcb5dc79SHONG Yifan	}
253*bcb5dc79SHONG Yifan
254*bcb5dc79SHONG Yifan	return language.GenerateResult{
255*bcb5dc79SHONG Yifan		Gen:     rules,
256*bcb5dc79SHONG Yifan		Imports: imports,
257*bcb5dc79SHONG Yifan		Empty:   generateEmpty(args),
258*bcb5dc79SHONG Yifan	}
259*bcb5dc79SHONG Yifan}
260*bcb5dc79SHONG Yifan
261*bcb5dc79SHONG Yifanfunc getBzlFileLoads(path string) ([]string, error) {
262*bcb5dc79SHONG Yifan	f, err := ioutil.ReadFile(path)
263*bcb5dc79SHONG Yifan	if err != nil {
264*bcb5dc79SHONG Yifan		return nil, fmt.Errorf("ioutil.ReadFile(%q) error: %v", path, err)
265*bcb5dc79SHONG Yifan	}
266*bcb5dc79SHONG Yifan	ast, err := build.ParseBuild(path, f)
267*bcb5dc79SHONG Yifan	if err != nil {
268*bcb5dc79SHONG Yifan		return nil, fmt.Errorf("build.Parse(%q) error: %v", f, err)
269*bcb5dc79SHONG Yifan	}
270*bcb5dc79SHONG Yifan
271*bcb5dc79SHONG Yifan	var loads []string
272*bcb5dc79SHONG Yifan	build.WalkOnce(ast, func(expr *build.Expr) {
273*bcb5dc79SHONG Yifan		n := *expr
274*bcb5dc79SHONG Yifan		if l, ok := n.(*build.LoadStmt); ok {
275*bcb5dc79SHONG Yifan			loads = append(loads, l.Module.Value)
276*bcb5dc79SHONG Yifan		}
277*bcb5dc79SHONG Yifan	})
278*bcb5dc79SHONG Yifan	sort.Strings(loads)
279*bcb5dc79SHONG Yifan
280*bcb5dc79SHONG Yifan	return loads, nil
281*bcb5dc79SHONG Yifan}
282*bcb5dc79SHONG Yifan
283*bcb5dc79SHONG Yifanfunc isBzlSourceFile(f string) bool {
284*bcb5dc79SHONG Yifan	return strings.HasSuffix(f, fileType) && !ignoreSuffix.Matches(f)
285*bcb5dc79SHONG Yifan}
286*bcb5dc79SHONG Yifan
287*bcb5dc79SHONG Yifan// generateEmpty generates the list of rules that don't need to exist in the
288*bcb5dc79SHONG Yifan// BUILD file any more.
289*bcb5dc79SHONG Yifan// For each bzl_library rule in args.File that only has srcs that aren't in
290*bcb5dc79SHONG Yifan// args.RegularFiles or args.GenFiles, add a bzl_library with no srcs or deps.
291*bcb5dc79SHONG Yifan// That will let Gazelle delete bzl_library rules after the corresponding .bzl
292*bcb5dc79SHONG Yifan// files are deleted.
293*bcb5dc79SHONG Yifanfunc generateEmpty(args language.GenerateArgs) []*rule.Rule {
294*bcb5dc79SHONG Yifan	var ret []*rule.Rule
295*bcb5dc79SHONG Yifan	if args.File == nil {
296*bcb5dc79SHONG Yifan		return ret
297*bcb5dc79SHONG Yifan	}
298*bcb5dc79SHONG Yifan	for _, r := range args.File.Rules {
299*bcb5dc79SHONG Yifan		if r.Kind() != "bzl_library" {
300*bcb5dc79SHONG Yifan			continue
301*bcb5dc79SHONG Yifan		}
302*bcb5dc79SHONG Yifan		name := r.AttrString("name")
303*bcb5dc79SHONG Yifan
304*bcb5dc79SHONG Yifan		exists := make(map[string]bool)
305*bcb5dc79SHONG Yifan		for _, f := range args.RegularFiles {
306*bcb5dc79SHONG Yifan			exists[f] = true
307*bcb5dc79SHONG Yifan		}
308*bcb5dc79SHONG Yifan		for _, f := range args.GenFiles {
309*bcb5dc79SHONG Yifan			exists[f] = true
310*bcb5dc79SHONG Yifan		}
311*bcb5dc79SHONG Yifan		for _, r := range args.File.Rules {
312*bcb5dc79SHONG Yifan			srcsExist := false
313*bcb5dc79SHONG Yifan			for _, f := range r.AttrStrings("srcs") {
314*bcb5dc79SHONG Yifan				if exists[f] {
315*bcb5dc79SHONG Yifan					srcsExist = true
316*bcb5dc79SHONG Yifan					break
317*bcb5dc79SHONG Yifan				}
318*bcb5dc79SHONG Yifan			}
319*bcb5dc79SHONG Yifan			if !srcsExist {
320*bcb5dc79SHONG Yifan				ret = append(ret, rule.NewRule("bzl_library", name))
321*bcb5dc79SHONG Yifan			}
322*bcb5dc79SHONG Yifan		}
323*bcb5dc79SHONG Yifan	}
324*bcb5dc79SHONG Yifan	return ret
325*bcb5dc79SHONG Yifan}
326*bcb5dc79SHONG Yifan
327*bcb5dc79SHONG Yifantype srcsList []string
328*bcb5dc79SHONG Yifan
329*bcb5dc79SHONG Yifanfunc (s srcsList) Contains(m string) bool {
330*bcb5dc79SHONG Yifan	for _, e := range s {
331*bcb5dc79SHONG Yifan		if e == m {
332*bcb5dc79SHONG Yifan			return true
333*bcb5dc79SHONG Yifan		}
334*bcb5dc79SHONG Yifan	}
335*bcb5dc79SHONG Yifan	return false
336*bcb5dc79SHONG Yifan}
337*bcb5dc79SHONG Yifan
338*bcb5dc79SHONG Yifan// checkInternalVisibility overrides the given visibility if the package is
339*bcb5dc79SHONG Yifan// internal.
340*bcb5dc79SHONG Yifanfunc checkInternalVisibility(rel, visibility string) string {
341*bcb5dc79SHONG Yifan	if i := pathtools.Index(rel, "internal"); i > 0 {
342*bcb5dc79SHONG Yifan		visibility = fmt.Sprintf("//%s:__subpackages__", rel[:i-1])
343*bcb5dc79SHONG Yifan	} else if i := pathtools.Index(rel, "private"); i > 0 {
344*bcb5dc79SHONG Yifan		visibility = fmt.Sprintf("//%s:__subpackages__", rel[:i-1])
345*bcb5dc79SHONG Yifan	} else if pathtools.HasPrefix(rel, "internal") || pathtools.HasPrefix(rel, "private") {
346*bcb5dc79SHONG Yifan		visibility = "//:__subpackages__"
347*bcb5dc79SHONG Yifan	}
348*bcb5dc79SHONG Yifan	return visibility
349*bcb5dc79SHONG Yifan}
350