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