Skip to content

Commit fdc6268

Browse files
authored
Support multi-symbol replace_load correctly (#1366)
The logic for removing old loading symbols replaced by `replace_load` was flawed. It would leave behind old (redundant) loads, iff the `replace_load` was to replace two symbols from the same location. This change simplifies how loads are replaced by simply keeping track of non-replaced loads rather than trying to remove from the list with index manipulation. I've added a few more test cases. Most of these new tests will fail on the old code.
1 parent b64e1da commit fdc6268

File tree

3 files changed

+92
-29
lines changed

3 files changed

+92
-29
lines changed

.bazelversion

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
8.2.1

edit/edit.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,17 +1192,16 @@ func ReplaceLoad(stmts []build.Expr, location string, from, to []string) []build
11921192
continue
11931193
}
11941194

1195+
var loadTo, loadFrom []*build.Ident
11951196
for i, to := range load.To {
1196-
if toSymbols[to.Name] {
1197-
if i < len(load.From)-1 {
1198-
load.From = append(load.From[:i], load.From[i+1:]...)
1199-
load.To = append(load.To[:i], load.To[i+1:]...)
1200-
} else {
1201-
load.From = load.From[:i]
1202-
load.To = load.To[:i]
1203-
}
1197+
// Only add the load to the statement if it will NOT be replaced by a new load.
1198+
if !toSymbols[to.Name] {
1199+
loadTo = append(loadTo, load.To[i])
1200+
loadFrom = append(loadFrom, load.From[i])
12041201
}
12051202
}
1203+
load.To = loadTo
1204+
load.From = loadFrom
12061205

12071206
if len(load.To) > 0 {
12081207
all = append(all, load)

edit/edit_test.go

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -162,42 +162,105 @@ load("other loc", "symbol")`,
162162
}
163163

164164
func TestReplaceLoad(t *testing.T) {
165-
tests := []struct{ input, expected string }{
165+
tests := []struct {
166+
name string
167+
input string
168+
location string
169+
from []string
170+
to []string
171+
expected string
172+
}{
166173
{
167-
``,
168-
`load("new_location", "symbol")`,
174+
name: "add_symbol",
175+
input: ``,
176+
location: "new_location",
177+
from: []string{"symbol"},
178+
to: []string{"symbol"},
179+
expected: `load("new_location", "symbol")`,
169180
},
170181
{
171-
`load("location", "symbol")`,
172-
`load("new_location", "symbol")`,
182+
name: "replace_location",
183+
input: `load("location", "symbol")`,
184+
location: "new_location",
185+
from: []string{"symbol"},
186+
to: []string{"symbol"},
187+
expected: `load("new_location", "symbol")`,
173188
},
174189
{
175-
`load("location", "other", "symbol")`,
176-
`load("location", "other")
190+
name: "replace_location_one_of_multiple",
191+
input: `load("location", "other", "symbol")`,
192+
location: "new_location",
193+
from: []string{"symbol"},
194+
to: []string{"symbol"},
195+
expected: `load("location", "other")
177196
load("new_location", "symbol")`,
178197
},
179198
{
180-
`load("location", symbol = "other")`,
181-
`load("new_location", "symbol")`,
199+
name: "replace_location_alias",
200+
input: `load("location", symbol = "other")`,
201+
location: "new_location",
202+
from: []string{"symbol"},
203+
to: []string{"symbol"},
204+
expected: `load("new_location", "symbol")`,
182205
},
183206
{
184-
`load("other loc", "symbol")
207+
name: "collapse_duplicate_symbol",
208+
input: `load("other loc", "symbol")
185209
load("location", "symbol")`,
186-
`load("new_location", "symbol")`,
210+
location: "new_location",
211+
from: []string{"symbol"},
212+
to: []string{"symbol"},
213+
expected: `load("new_location", "symbol")`,
214+
},
215+
{
216+
name: "replace_multiple_same_location",
217+
input: `load("location", "symbol_a", "symbol_b", "symbol_c")`,
218+
location: "new_location",
219+
from: []string{"symbol_a", "symbol_b", "symbol_c"},
220+
to: []string{"symbol_a", "symbol_b", "symbol_c"},
221+
expected: `load("new_location", "symbol_a", "symbol_b", "symbol_c")`,
222+
},
223+
{
224+
name: "replace_multiple_same_location_out_of_order",
225+
input: `load("location", "symbol_a", "symbol_b", "symbol_c")`,
226+
location: "new_location",
227+
from: []string{"symbol_c", "symbol_a", "symbol_b"},
228+
to: []string{"symbol_c", "symbol_a", "symbol_b"},
229+
expected: `load("new_location", "symbol_a", "symbol_b", "symbol_c")`,
230+
},
231+
{
232+
name: "replace_multiple_same_location_partial",
233+
input: `load("location", "symbol_a", "symbol_b", "symbol_c")`,
234+
location: "new_location",
235+
from: []string{"symbol_a", "symbol_b"},
236+
to: []string{"symbol_a", "symbol_b"},
237+
expected: `load("location", "symbol_c")
238+
load("new_location", "symbol_a", "symbol_b")`,
239+
},
240+
{
241+
name: "replace_multiple_same_location_partial_out_of_order",
242+
input: `load("location", "symbol_a", "symbol_b", "symbol_c")`,
243+
location: "new_location",
244+
from: []string{"symbol_b", "symbol_a"},
245+
to: []string{"symbol_b", "symbol_a"},
246+
expected: `load("location", "symbol_c")
247+
load("new_location", "symbol_a", "symbol_b")`,
187248
},
188249
}
189250

190251
for _, tst := range tests {
191-
bld, err := build.Parse("BUILD", []byte(tst.input))
192-
if err != nil {
193-
t.Error(err)
194-
continue
195-
}
196-
bld.Stmt = ReplaceLoad(bld.Stmt, "new_location", []string{"symbol"}, []string{"symbol"})
197-
got := strings.TrimSpace(string(build.Format(bld)))
198-
if got != tst.expected {
199-
t.Errorf("maybeReplaceLoad(%s): got %s, expected %s", tst.input, got, tst.expected)
200-
}
252+
t.Run(tst.name, func(t *testing.T) {
253+
bld, err := build.Parse("BUILD", []byte(tst.input))
254+
if err != nil {
255+
t.Error(err)
256+
return
257+
}
258+
bld.Stmt = ReplaceLoad(bld.Stmt, tst.location, tst.from, tst.to)
259+
got := strings.TrimSpace(string(build.Format(bld)))
260+
if got != tst.expected {
261+
t.Errorf("ReplaceLoad(%s): got %s, expected %s", tst.input, got, tst.expected)
262+
}
263+
})
201264
}
202265
}
203266

0 commit comments

Comments
 (0)