...

Source file src/github.com/bazelbuild/buildtools/warn/warn_bazel.go

Documentation: github.com/bazelbuild/buildtools/warn

     1  /*
     2  Copyright 2020 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // General Bazel-related warnings
    18  
    19  package warn
    20  
    21  import (
    22  	"fmt"
    23  	"strings"
    24  
    25  	"github.com/bazelbuild/buildtools/build"
    26  )
    27  
    28  var functionsWithPositionalArguments = map[string]bool{
    29  	"distribs":            true,
    30  	"exports_files":       true,
    31  	"licenses":            true,
    32  	"print":               true,
    33  	"register_toolchains": true,
    34  	"vardef":              true,
    35  }
    36  
    37  func constantGlobWarning(f *build.File) []*LinterFinding {
    38  	switch f.Type {
    39  	case build.TypeBuild, build.TypeWorkspace, build.TypeBzl:
    40  	default:
    41  		// Not applicable
    42  		return nil
    43  	}
    44  
    45  	findings := []*LinterFinding{}
    46  	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
    47  		call, ok := expr.(*build.CallExpr)
    48  		if !ok || len(call.List) == 0 {
    49  			return
    50  		}
    51  		ident, ok := (call.X).(*build.Ident)
    52  		if !ok || ident.Name != "glob" {
    53  			return
    54  		}
    55  		patterns, ok := call.List[0].(*build.ListExpr)
    56  		if !ok {
    57  			return
    58  		}
    59  		for _, expr := range patterns.List {
    60  			str, ok := expr.(*build.StringExpr)
    61  			if !ok {
    62  				continue
    63  			}
    64  			if !strings.Contains(str.Value, "*") {
    65  				message := fmt.Sprintf(
    66  					`Glob pattern %q has no wildcard ('*'). Constant patterns can be error-prone, move the file outside the glob.`, str.Value)
    67  				findings = append(findings, makeLinterFinding(expr, message))
    68  				return // at most one warning per glob
    69  			}
    70  		}
    71  	})
    72  	return findings
    73  }
    74  
    75  func nativeInBuildFilesWarning(f *build.File) []*LinterFinding {
    76  	if f.Type != build.TypeBuild {
    77  		return nil
    78  	}
    79  
    80  	findings := []*LinterFinding{}
    81  	build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
    82  		// Search for `native.xxx` nodes
    83  		dot, ok := (*expr).(*build.DotExpr)
    84  		if !ok {
    85  			return
    86  		}
    87  		ident, ok := dot.X.(*build.Ident)
    88  		if !ok || ident.Name != "native" {
    89  			return
    90  		}
    91  
    92  		findings = append(findings,
    93  			makeLinterFinding(ident,
    94  				`The "native" module shouldn't be used in BUILD files, its members are available as global symbols.`,
    95  				LinterReplacement{expr, &build.Ident{Name: dot.Name}}))
    96  	})
    97  	return findings
    98  }
    99  
   100  func nativePackageWarning(f *build.File) []*LinterFinding {
   101  	if f.Type != build.TypeBzl {
   102  		return nil
   103  	}
   104  
   105  	findings := []*LinterFinding{}
   106  	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
   107  		// Search for `native.package()` nodes
   108  		call, ok := expr.(*build.CallExpr)
   109  		if !ok {
   110  			return
   111  		}
   112  		dot, ok := call.X.(*build.DotExpr)
   113  		if !ok || dot.Name != "package" {
   114  			return
   115  		}
   116  		ident, ok := dot.X.(*build.Ident)
   117  		if !ok || ident.Name != "native" {
   118  			return
   119  		}
   120  
   121  		findings = append(findings,
   122  			makeLinterFinding(call, `"native.package()" shouldn't be used in .bzl files.`))
   123  	})
   124  	return findings
   125  }
   126  
   127  func duplicatedNameWarning(f *build.File) []*LinterFinding {
   128  	if f.Type != build.TypeBuild && f.Type != build.TypeWorkspace {
   129  		// Not applicable to .bzl files.
   130  		return nil
   131  	}
   132  
   133  	findings := []*LinterFinding{}
   134  	names := make(map[string]int) // map from name to line number
   135  	msg := `A rule with name %q was already found on line %d. ` +
   136  		`Even if it's valid for Blaze, this may confuse other tools. ` +
   137  		`Please rename it and use different names.`
   138  
   139  	for _, rule := range f.Rules("") {
   140  		name := rule.ExplicitName()
   141  		if name == "" {
   142  			continue
   143  		}
   144  		start, _ := rule.Call.Span()
   145  		if line, ok := names[name]; ok {
   146  			finding := makeLinterFinding(rule.Call, fmt.Sprintf(msg, name, line))
   147  			if nameNode := rule.Attr("name"); nameNode != nil {
   148  				finding.Start, finding.End = nameNode.Span()
   149  				start = finding.Start
   150  			}
   151  			findings = append(findings, finding)
   152  		} else {
   153  			names[name] = start.Line
   154  		}
   155  	}
   156  	return findings
   157  }
   158  
   159  func positionalArgumentsWarning(call *build.CallExpr, pkg string) *LinterFinding {
   160  	if id, ok := call.X.(*build.Ident); !ok || functionsWithPositionalArguments[id.Name] {
   161  		return nil
   162  	}
   163  	for _, arg := range call.List {
   164  		if _, ok := arg.(*build.AssignExpr); ok || arg == nil {
   165  			continue
   166  		}
   167  		return makeLinterFinding(arg, "All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.")
   168  	}
   169  	return nil
   170  }
   171  
   172  func argsKwargsInBuildFilesWarning(f *build.File) []*LinterFinding {
   173  	if f.Type != build.TypeBuild {
   174  		return nil
   175  	}
   176  
   177  	findings := []*LinterFinding{}
   178  	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
   179  		// Search for function call nodes
   180  		call, ok := expr.(*build.CallExpr)
   181  		if !ok {
   182  			return
   183  		}
   184  		for _, param := range call.List {
   185  			unary, ok := param.(*build.UnaryExpr)
   186  			if !ok {
   187  				continue
   188  			}
   189  			switch unary.Op {
   190  			case "*":
   191  				findings = append(findings,
   192  					makeLinterFinding(param, `*args are not allowed in BUILD files.`))
   193  			case "**":
   194  				findings = append(findings,
   195  					makeLinterFinding(param, `**kwargs are not allowed in BUILD files.`))
   196  			}
   197  		}
   198  	})
   199  	return findings
   200  }
   201  
   202  func printWarning(f *build.File) []*LinterFinding {
   203  	if f.Type == build.TypeDefault {
   204  		// Only applicable to Bazel files
   205  		return nil
   206  	}
   207  
   208  	findings := []*LinterFinding{}
   209  	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
   210  		call, ok := expr.(*build.CallExpr)
   211  		if !ok {
   212  			return
   213  		}
   214  		ident, ok := (call.X).(*build.Ident)
   215  		if !ok || ident.Name != "print" {
   216  			return
   217  		}
   218  		findings = append(findings,
   219  			makeLinterFinding(expr, `"print()" is a debug function and shouldn't be submitted.`))
   220  	})
   221  	return findings
   222  }
   223  

View as plain text