1// Warnings about deprecated Bazel-related operations 2 3package warn 4 5import ( 6 "fmt" 7 8 "github.com/bazelbuild/buildtools/build" 9) 10 11func depsetUnionWarning(f *build.File) []*LinterFinding { 12 var findings []*LinterFinding 13 addWarning := func(expr build.Expr) { 14 findings = append(findings, 15 makeLinterFinding(expr, `Depsets should be joined using the "depset()" constructor.`)) 16 } 17 18 types := detectTypes(f) 19 build.Walk(f, func(expr build.Expr, stack []build.Expr) { 20 switch expr := expr.(type) { 21 case *build.BinaryExpr: 22 // `depset1 + depset2` or `depset1 | depset2` 23 if types[expr.X] != Depset && types[expr.Y] != Depset { 24 return 25 } 26 switch expr.Op { 27 case "+", "|": 28 addWarning(expr) 29 } 30 case *build.AssignExpr: 31 // `depset1 += depset2` or `depset1 |= depset2` 32 if types[expr.LHS] != Depset && types[expr.RHS] != Depset { 33 return 34 } 35 switch expr.Op { 36 case "+=", "|=": 37 addWarning(expr) 38 } 39 case *build.CallExpr: 40 // `depset1.union(depset2)` 41 if len(expr.List) == 0 { 42 return 43 } 44 dot, ok := expr.X.(*build.DotExpr) 45 if !ok { 46 return 47 } 48 if dot.Name != "union" { 49 return 50 } 51 if types[dot.X] != Depset && types[expr.List[0]] != Depset { 52 return 53 } 54 addWarning(expr) 55 } 56 }) 57 return findings 58} 59 60func depsetIterationWarning(f *build.File) []*LinterFinding { 61 var findings []*LinterFinding 62 63 addFinding := func(expr *build.Expr) { 64 _, end := (*expr).Span() 65 newNode := &build.CallExpr{ 66 X: &build.DotExpr{ 67 X: *expr, 68 Name: "to_list", 69 }, 70 End: build.End{Pos: end}, 71 } 72 findings = append(findings, 73 makeLinterFinding(*expr, `Depset iteration is deprecated, use the "to_list()" method instead.`, LinterReplacement{expr, newNode})) 74 } 75 76 types := detectTypes(f) 77 build.WalkPointers(f, func(e *build.Expr, stack []build.Expr) { 78 switch expr := (*e).(type) { 79 case *build.ForStmt: 80 if types[expr.X] != Depset { 81 return 82 } 83 addFinding(&expr.X) 84 case *build.ForClause: 85 if types[expr.X] != Depset { 86 return 87 } 88 addFinding(&expr.X) 89 case *build.BinaryExpr: 90 if expr.Op != "in" && expr.Op != "not in" { 91 return 92 } 93 if types[expr.Y] != Depset { 94 return 95 } 96 addFinding(&expr.Y) 97 case *build.CallExpr: 98 ident, ok := expr.X.(*build.Ident) 99 if !ok { 100 return 101 } 102 switch ident.Name { 103 case "all", "any", "depset", "len", "sorted", "max", "min", "list", "tuple": 104 if len(expr.List) != 1 { 105 return 106 } 107 if types[expr.List[0]] != Depset { 108 return 109 } 110 addFinding(&expr.List[0]) 111 if ident.Name == "list" { 112 // `list(d.to_list())` can be simplified to just `d.to_list()` 113 findings[len(findings)-1].Replacement[0].Old = e 114 } 115 case "zip": 116 for i, arg := range expr.List { 117 if types[arg] != Depset { 118 continue 119 } 120 addFinding(&expr.List[i]) 121 } 122 } 123 } 124 return 125 }) 126 return findings 127} 128 129func overlyNestedDepsetWarning(f *build.File) []*LinterFinding { 130 var findings []*LinterFinding 131 build.WalkStatements(f, func(expr build.Expr, stack []build.Expr) { 132 // Are we inside a for-loop? 133 isForLoop := false 134 for _, e := range stack { 135 if _, ok := e.(*build.ForStmt); ok { 136 isForLoop = true 137 break 138 } 139 } 140 if !isForLoop { 141 return 142 } 143 144 // Search for assignment statements 145 assign, ok := expr.(*build.AssignExpr) 146 if !ok { 147 return 148 } 149 // Is the LHS an ident? 150 lhs, ok := assign.LHS.(*build.Ident) 151 if !ok { 152 return 153 } 154 // Is the RHS a depset constructor? 155 call, ok := assign.RHS.(*build.CallExpr) 156 if !ok { 157 return 158 } 159 if ident, ok := call.X.(*build.Ident); !ok || ident.Name != "depset" { 160 return 161 } 162 _, _, param := getParam(call.List, "transitive") 163 if param == nil { 164 return 165 } 166 transitives, ok := param.RHS.(*build.ListExpr) 167 if !ok { 168 return 169 } 170 for _, transitive := range transitives.List { 171 if ident, ok := transitive.(*build.Ident); ok && ident.Name == lhs.Name { 172 findings = append(findings, makeLinterFinding(assign, fmt.Sprintf("Depset %q is potentially overly nested.", lhs.Name))) 173 return 174 } 175 } 176 }) 177 return findings 178} 179