Repository: bazelbuild/buildtools
Pull request #1103 (2022-11-25 16:31:30)

Make the DetectTypes function public.
It can be useful for other analyzers written on top of Buildifier.


Patch:
diff --git a/warn/types.go b/warn/types.go
index 2b7e9cd..07dbb6c 100644
--- a/warn/types.go
+++ b/warn/types.go
@@ -61,7 +61,11 @@ func (t Type) String() string {
 
 var intRegexp = regexp.MustCompile(`^([0-9]+|0[Xx][0-9A-Fa-f]+|0[Oo][0-7]+)$`)
 
-func detectTypes(f *build.File) map[build.Expr]Type {
+// DetectTypes tries to infer the type of expressions in the current file, using basic heuristics.
+//
+// Warning: the types inferred by the function might change in the future, as we update the
+// heuristics.
+func DetectTypes(f *build.File) map[build.Expr]Type {
 	variables := make(map[int]Type)
 	result := make(map[build.Expr]Type)
 
@@ -196,9 +200,9 @@ func detectTypes(f *build.File) map[build.Expr]Type {
 // named parameters of functions. E.g. for `foo(x, y = z)` it visits `foo`, `x`, and `z`.
 // In the following example `x` in the last line shouldn't be recognised as int, but 'y' should:
 //
-//    x = 3
-//    y = 5
-//    foo(x = y)
+//	x = 3
+//	y = 5
+//	foo(x = y)
 func walkOnce(node build.Expr, env *bzlenv.Environment, fct func(e *build.Expr, env *bzlenv.Environment)) {
 	switch expr := node.(type) {
 	case *build.CallExpr:
diff --git a/warn/warn_bazel_api.go b/warn/warn_bazel_api.go
index 3d74f1d..0c23803 100644
--- a/warn/warn_bazel_api.go
+++ b/warn/warn_bazel_api.go
@@ -360,16 +360,17 @@ func attrConfigurationWarning(f *build.File) []*LinterFinding {
 				makeLinterFinding(param, `cfg = "data" for attr definitions has no effect and should be removed.`,
 					LinterReplacement{expr, &newCall}))
 
-		case "host": {
-			newCall.List = append([]build.Expr{}, newCall.List...)
-			newParam := newCall.List[i].Copy().(*build.AssignExpr)
-			newRHS := newParam.RHS.Copy().(*build.StringExpr)
-			newRHS.Value = "exec"
-			newParam.RHS = newRHS
-			newCall.List[i] = newParam
-			findings = append(findings,
-				makeLinterFinding(param, `cfg = "host" for attr definitions should be replaced by cfg = "exec".`,
-					LinterReplacement{expr, &newCall}))
+		case "host":
+			{
+				newCall.List = append([]build.Expr{}, newCall.List...)
+				newParam := newCall.List[i].Copy().(*build.AssignExpr)
+				newRHS := newParam.RHS.Copy().(*build.StringExpr)
+				newRHS.Value = "exec"
+				newParam.RHS = newRHS
+				newCall.List[i] = newParam
+				findings = append(findings,
+					makeLinterFinding(param, `cfg = "host" for attr definitions should be replaced by cfg = "exec".`,
+						LinterReplacement{expr, &newCall}))
 			}
 
 		default:
@@ -383,7 +384,7 @@ func attrConfigurationWarning(f *build.File) []*LinterFinding {
 func depsetItemsWarning(f *build.File) []*LinterFinding {
 	var findings []*LinterFinding
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
 		call, ok := (*expr).(*build.CallExpr)
 		if !ok {
@@ -721,7 +722,7 @@ func contextArgsAPIWarning(f *build.File) []*LinterFinding {
 	}
 
 	var findings []*LinterFinding
-	types := detectTypes(f)
+	types := DetectTypes(f)
 
 	build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
 		// Search for `<ctx.actions.args>.add()` nodes
diff --git a/warn/warn_bazel_operation.go b/warn/warn_bazel_operation.go
index b455e4a..6bf8b08 100644
--- a/warn/warn_bazel_operation.go
+++ b/warn/warn_bazel_operation.go
@@ -31,7 +31,7 @@ func depsetUnionWarning(f *build.File) []*LinterFinding {
 			makeLinterFinding(expr, `Depsets should be joined using the "depset()" constructor.`))
 	}
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
 		switch expr := expr.(type) {
 		case *build.BinaryExpr:
@@ -89,7 +89,7 @@ func depsetIterationWarning(f *build.File) []*LinterFinding {
 			makeLinterFinding(*expr, `Depset iteration is deprecated, use the "to_list()" method instead.`, LinterReplacement{expr, newNode}))
 	}
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.WalkPointers(f, func(e *build.Expr, stack []build.Expr) {
 		switch expr := (*e).(type) {
 		case *build.ForStmt:
diff --git a/warn/warn_control_flow.go b/warn/warn_control_flow.go
index ed9da0a..5ff0d09 100644
--- a/warn/warn_control_flow.go
+++ b/warn/warn_control_flow.go
@@ -229,8 +229,9 @@ func noEffectWarning(f *build.File) []*LinterFinding {
 // single statement that are either defined outside the node and used inside,
 // or defined inside the node and can be used outside.
 // Examples of idents that don't fall into either of the categories:
-//   * Named arguments of function calls: `foo` in `f(foo = "bar")`
-//   * Iterators of comprehension nodes and its usages: `x` in `[f(x) for x in y]`
+//   - Named arguments of function calls: `foo` in `f(foo = "bar")`
+//   - Iterators of comprehension nodes and its usages: `x` in `[f(x) for x in y]`
+//
 // Statements that contain other statements (for-loops, if-else blocks) are not
 // traversed inside.
 func extractIdentsFromStmt(stmt build.Expr) (assigned, used map[*build.Ident]bool) {
@@ -541,7 +542,7 @@ func redefinedVariableWarning(f *build.File) []*LinterFinding {
 	findings := []*LinterFinding{}
 	definedSymbols := make(map[string]bool)
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	for _, s := range f.Stmt {
 		// look for all assignments in the scope
 		as, ok := s.(*build.AssignExpr)
diff --git a/warn/warn_operation.go b/warn/warn_operation.go
index 0280023..61446cc 100644
--- a/warn/warn_operation.go
+++ b/warn/warn_operation.go
@@ -30,7 +30,7 @@ func dictionaryConcatenationWarning(f *build.File) []*LinterFinding {
 			makeLinterFinding(expr, "Dictionary concatenation is deprecated."))
 	}
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
 		switch expr := expr.(type) {
 		case *build.BinaryExpr:
@@ -60,7 +60,7 @@ func stringIterationWarning(f *build.File) []*LinterFinding {
 			makeLinterFinding(expr, "String iteration is deprecated."))
 	}
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.Walk(f, func(expr build.Expr, stack []build.Expr) {
 		switch expr := expr.(type) {
 		case *build.ForStmt:
@@ -99,7 +99,7 @@ func stringIterationWarning(f *build.File) []*LinterFinding {
 func integerDivisionWarning(f *build.File) []*LinterFinding {
 	var findings []*LinterFinding
 
-	types := detectTypes(f)
+	types := DetectTypes(f)
 	build.WalkPointers(f, func(e *build.Expr, stack []build.Expr) {
 		switch expr := (*e).(type) {
 		case *build.BinaryExpr:


Test patch:
diff --git a/warn/types_test.go b/warn/types_test.go
index c7233fd..6ec4caa 100644
--- a/warn/types_test.go
+++ b/warn/types_test.go
@@ -32,7 +32,7 @@ func checkTypes(t *testing.T, input, output string) {
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	types := detectTypes(f)
+	types := DetectTypes(f)
 
 	var edit func(expr build.Expr, stack []build.Expr) build.Expr
 	edit = func(expr build.Expr, stack []build.Expr) build.Expr {