Skip to content

Commit 9bdafcf

Browse files
Disable bzl-visibility lint if the target file has a visibility() declaration (#1439)
* Disable bzl-visibility lint if the target file has a `visibility()` declaration. The official docs for this lint say: > This lint predates the load visibility feature and is unnecessary in workspaces where .bzl files declare visibilities. However the lint can sometimes get in the way, by warning about instances where the usage is actually intended. Since `visibility()` is more explicit, and more strictly enforced, there is no need for the lint to return any warnings if the target file has a visibility declaration. MARKDOWN=true * Addressed edge case where call function is not an ident. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Added a test that files without visibility() still enforce the check. MARKDOWN=true --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent f026de8 commit 9bdafcf

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

warn/warn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ var FileWarningMap = map[string]func(f *build.File) []*LinterFinding{
124124
"attr-output-default": attrOutputDefaultWarning,
125125
"attr-single-file": attrSingleFileWarning,
126126
"build-args-kwargs": argsKwargsInBuildFilesWarning,
127-
"bzl-visibility": bzlVisibilityWarning,
128127
"canonical-repository": canonicalRepositoryWarning,
129128
"confusing-name": confusingNameWarning,
130129
"constant-glob": constantGlobWarning,
@@ -172,6 +171,7 @@ var FileWarningMap = map[string]func(f *build.File) []*LinterFinding{
172171

173172
// MultiFileWarningMap lists the warnings that run on the whole file, but may use other files.
174173
var MultiFileWarningMap = map[string]func(f *build.File, fileReader *FileReader) []*LinterFinding{
174+
"bzl-visibility": bzlVisibilityWarning,
175175
"deprecated-function": deprecatedFunctionWarning,
176176
"git-repository": nativeGitRepositoryWarning,
177177
"http-archive": nativeHTTPArchiveWarning,

warn/warn_visibility.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,38 @@ import (
2424
"strings"
2525

2626
"github.com/bazelbuild/buildtools/build"
27+
"github.com/bazelbuild/buildtools/labels"
2728
)
2829

2930
var internalDirectory = regexp.MustCompile("/(internal|private)[/:]")
3031

31-
func bzlVisibilityWarning(f *build.File) []*LinterFinding {
32+
func hasVisibilityStatement(f *build.File, load *build.LoadStmt, fileReader *FileReader) bool {
33+
if fileReader == nil {
34+
return false
35+
}
36+
label := labels.ParseRelative(load.Module.Value, f.Pkg)
37+
if label.Repository != "" || label.Target == "" {
38+
return false
39+
}
40+
loadedFile := fileReader.GetFile(label.Package, label.Target)
41+
if loadedFile == nil {
42+
return false
43+
}
44+
for _, stmt := range loadedFile.Stmt {
45+
call, ok := stmt.(*build.CallExpr)
46+
if !ok {
47+
continue
48+
}
49+
// We don't try to be exhaustive here, but rather only catch the most
50+
// common cases of visibility declarations.
51+
if ident, ok := call.X.(*build.Ident); ok && ident.Name == "visibility" {
52+
return true
53+
}
54+
}
55+
return false
56+
}
57+
58+
func bzlVisibilityWarning(f *build.File, fileReader *FileReader) []*LinterFinding {
3259
var findings []*LinterFinding
3360

3461
if f.WorkspaceRoot == "" {
@@ -58,6 +85,13 @@ func bzlVisibilityWarning(f *build.File) []*LinterFinding {
5885
}
5986
}
6087

88+
if hasVisibilityStatement(f, load, fileReader) {
89+
// The module has a visibility statement, which is a more explicit
90+
// (and strongly-enforced) mechanism to specify visibility. No need
91+
// to issue a warning using the older and less explicit mechanism.
92+
continue
93+
}
94+
6195
path := f.CanonicalPath() // Canonical name of the file
6296
chunks := internalDirectory.Split(module, 2)
6397
if len(chunks) < 2 {

warn/warn_visibility_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,40 @@ bar1()
108108
[]string{},
109109
scopeEverywhere)
110110
}
111+
112+
// Test that the warning is not issued if the module has a visibility statement.
113+
func TestBzlVisibilityWithVisibilityStatement(t *testing.T) {
114+
defer setUpFileReader(map[string]string{
115+
"foo/private/bar.bzl": `
116+
visibility([
117+
"//test/package:__subpackages__",
118+
])
119+
120+
abc = 1
121+
`,
122+
})()
123+
124+
checkFindings(t, "bzl-visibility", `
125+
load("//foo/private:bar.bzl", "abc")
126+
`,
127+
[]string{},
128+
scopeEverywhere)
129+
}
130+
131+
// Test that the warning *is* issued if the module does *not* have a visibility statement.
132+
func TestBzlVisibilityWithoutVisibilityStatement(t *testing.T) {
133+
defer setUpFileReader(map[string]string{
134+
"foo/private/bar.bzl": `
135+
136+
abc = 1
137+
`,
138+
})()
139+
140+
checkFindings(t, "bzl-visibility", `
141+
load("//foo/private:bar.bzl", "abc")
142+
`,
143+
[]string{
144+
`Module "//foo/private:bar.bzl" can only be loaded from files located inside`,
145+
},
146+
scopeEverywhere)
147+
}

0 commit comments

Comments
 (0)