| /* |
| Copyright 2020 Google LLC |
| |
| 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 |
| |
| https://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. |
| */ |
| |
| // Warnings about visibility of .bzl files |
| |
| package warn |
| |
| import ( |
| "fmt" |
| "regexp" |
| "strings" |
| |
| "github.com/bazelbuild/buildtools/build" |
| ) |
| |
| var internalDirectory = regexp.MustCompile("/(internal|private)[/:]") |
| |
| func bzlVisibilityWarning(f *build.File) []*LinterFinding { |
| var findings []*LinterFinding |
| |
| if f.WorkspaceRoot == "" { |
| // Empty workspace root means buildifier doesn't know the location of |
| // the file relative to the workspace directory and can't warn about .bzl |
| // file visibility correctly. |
| return findings |
| } |
| |
| for _, stmt := range f.Stmt { |
| load, ok := stmt.(*build.LoadStmt) |
| if !ok || load.Module == nil { |
| continue |
| } |
| |
| // A load statement may use a fully qualified module name (including a |
| // repository name). Buildifier should check if the repository name refers |
| // to the current repository, but because it doesn't know the current |
| // repository name it's better to assume that it matches the repository name |
| // in the load statement: this way it may miss some usages of private .bzl |
| // files that aren't supposed to be visible, but won't show false-positive |
| // warnings in case the private file is actually allowed to be used. |
| module := load.Module.Value |
| if strings.HasPrefix(module, "@") { |
| if chunks := strings.SplitN(module, "//", 2); len(chunks) == 2 { |
| module = "//" + chunks[1] |
| } |
| } |
| |
| path := f.CanonicalPath() // Canonical name of the file |
| chunks := internalDirectory.Split(module, 2) |
| if len(chunks) < 2 { |
| continue |
| } |
| |
| if strings.HasPrefix(path, chunks[0]) || |
| strings.HasPrefix(strings.Replace(path, "/javatests/", "/java/", 1), chunks[0]) { |
| continue |
| } |
| |
| findings = append(findings, makeLinterFinding( |
| load.Module, |
| fmt.Sprintf("Module %q can only be loaded from files located inside %q, not from %q.", load.Module.Value, chunks[0], path))) |
| } |
| |
| return findings |
| } |