Skip to content

Commit 8145bdd

Browse files
committed
cue/ast/astutil: update ast.File.Imports properly in Sanitize
Sanitize removes unused imports from its input files, that is, when a package is imported at the top of the file but not referenced. Sanitize updated the ast.File.Decls list, which was OK for cue/format to print out the file without the import, but it did not update ast.File.Imports, which is a flattened list of import specs used by the loader and the compiler. As a sanity check, `cue trim` rebuilds each package instance it trims before it writes the CUE files back to disk, to ensure it is not writing invalid CUE which could cause confusing errors or data loss. The rebuild then correctly failed with an "imported and not used" error. Teach TestTrimFiles to catch the same mistake by rebuilding the files as a new instance after the trimming has happened. We already had a test which is meant to remove an unused import, and since we didn't remove it properly per the above, the rebuild tried and failed to load the imported package: --- FAIL: TestTrimFiles/trim/rmimport (0.00s) quicktest.go:12: error: got non-nil value got: e`package "mod.test/blah/a" not found` Tweak Sanitize so that it keeps ast.File.Imports up to date. ast.File holding all imports in both Decls and Imports is a bit of a trap for any other user who wishes to add or remove any import, so I've also raised #3324 to propose phasing out ast.File.Imports. Updates #3206. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I7552ffcba32f451842ea7fc0f39d71f0a365a13b Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1198351 Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Matthew Sackman <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 23fc4b1 commit 8145bdd

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

cue/ast/astutil/sanitize.go

+10-7
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,19 @@ func (z *sanitizer) markUsed(s *scope, n *ast.Ident) bool {
168168
}
169169

170170
func (z *sanitizer) cleanImports() {
171-
z.file.VisitImports(func(d *ast.ImportDecl) {
172-
k := 0
173-
for _, s := range d.Specs {
174-
if _, ok := z.referenced[s]; ok {
175-
d.Specs[k] = s
176-
k++
171+
var fileImports []*ast.ImportSpec
172+
z.file.VisitImports(func(decl *ast.ImportDecl) {
173+
newLen := 0
174+
for _, spec := range decl.Specs {
175+
if _, ok := z.referenced[spec]; ok {
176+
fileImports = append(fileImports, spec)
177+
decl.Specs[newLen] = spec
178+
newLen++
177179
}
178180
}
179-
d.Specs = d.Specs[:k]
181+
decl.Specs = decl.Specs[:newLen]
180182
})
183+
z.file.Imports = fileImports
181184
}
182185

183186
func (z *sanitizer) handleIdent(s *scope, n *ast.Ident) bool {

tools/trim/trim_test.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ package trim
1717
import (
1818
"testing"
1919

20+
"cuelang.org/go/cue/build"
2021
"cuelang.org/go/cue/errors"
2122
"cuelang.org/go/internal/cuetdtest"
2223
"cuelang.org/go/internal/cuetxtar"
24+
"github.com/go-quicktest/qt"
2325
)
2426

2527
var (
@@ -43,8 +45,9 @@ func TestTrimFiles(t *testing.T) {
4345
a := t.Instance()
4446
ctx := t.Context()
4547
val := ctx.BuildInstance(a)
46-
// Note: don't check val.Err because there are deliberate
47-
// errors in some tests.
48+
// Note: don't require val.Err to be nil because there are deliberate
49+
// errors in some tests, to ensure trim still works even with some errors.
50+
hadError := val.Err() != nil
4851

4952
files := a.Files
5053

@@ -53,6 +56,19 @@ func TestTrimFiles(t *testing.T) {
5356
t.WriteErrors(errors.Promote(err, ""))
5457
}
5558

59+
// If the files could be built without an error before,
60+
// they should still build without an error after trimming.
61+
// This might not be true if, for example, unused imports are not removed.
62+
// Note that we need a new build.Instance to build the ast.Files from scratch again.
63+
if !hadError {
64+
a := build.NewContext().NewInstance("", nil)
65+
for _, file := range files {
66+
a.AddSyntax(file)
67+
}
68+
val := ctx.BuildInstance(a)
69+
qt.Assert(t, qt.IsNil(val.Err()))
70+
}
71+
5672
for _, f := range files {
5773
t.WriteFile(f)
5874
}

0 commit comments

Comments
 (0)