tools/fix: allow fixing non-essential simplification
First implementation is rewriting `_ | x` to `_`.
Change-Id: Idda745f5493dc092dd0a3677c52e7e79eee74aa3
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8231
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cmd/cue/cmd/fix.go b/cmd/cue/cmd/fix.go
index 30f4be2..2026654 100644
--- a/cmd/cue/cmd/fix.go
+++ b/cmd/cue/cmd/fix.go
@@ -54,6 +54,11 @@
return err
}
+ var opts []fix.Option
+ if flagSimplify.Bool(cmd) {
+ opts = append(opts, fix.Simplify())
+ }
+
if len(args) == 0 {
args = []string{"./..."}
@@ -81,7 +86,7 @@
Tools: true,
})
- errs := fix.Instances(instances)
+ errs := fix.Instances(instances, opts...)
if errs != nil && flagForce.Bool(cmd) {
return errs
diff --git a/tools/fix/fix.go b/tools/fix/fix.go
index 98f5ffd..b464270 100644
--- a/tools/fix/fix.go
+++ b/tools/fix/fix.go
@@ -28,8 +28,25 @@
"cuelang.org/go/cue/token"
)
+type Option func(*options)
+
+type options struct {
+ simplify bool
+}
+
+// Simplify enables fixes that simplify the code, but are not strictly
+// necessary.
+func Simplify() Option {
+ return func(o *options) { o.simplify = true }
+}
+
// File applies fixes to f and returns it. It alters the original f.
-func File(f *ast.File) *ast.File {
+func File(f *ast.File, o ...Option) *ast.File {
+ var options options
+ for _, f := range o {
+ f(&options)
+ }
+
// Rewrite integer division operations to use builtins.
f = astutil.Apply(f, func(c astutil.Cursor) bool {
n := c.Node()
@@ -248,5 +265,38 @@
// return true
// }, nil).(*ast.File)
+ if !options.simplify {
+ return f
+ }
+
+ // Rewrite disjunctions with _ to _.
+ f = astutil.Apply(f, func(c astutil.Cursor) bool {
+ if x := findTop(c.Node()); x != nil {
+ c.Replace(x)
+ }
+ return true
+ }, nil).(*ast.File)
+
return f
}
+
+func findTop(x ast.Node) ast.Expr {
+ switch x := x.(type) {
+ case *ast.BinaryExpr:
+ if x.Op != token.OR {
+ break
+ }
+ if v := findTop(x.X); v != nil {
+ return v
+ }
+ if v := findTop(x.Y); v != nil {
+ return v
+ }
+
+ case *ast.Ident:
+ if x.Name == "_" {
+ return x
+ }
+ }
+ return nil
+}
diff --git a/tools/fix/fix_test.go b/tools/fix/fix_test.go
index 83c1976..63f7f99 100644
--- a/tools/fix/fix_test.go
+++ b/tools/fix/fix_test.go
@@ -23,9 +23,10 @@
func TestFile(t *testing.T) {
testCases := []struct {
- name string
- in string
- out string
+ name string
+ in string
+ out string
+ simplify bool
}{{
name: "rewrite integer division",
in: `package foo
@@ -85,6 +86,14 @@
out: `
let y = foo
`,
+ }, {
+ simplify: true,
+ in: `
+ y: _ | {[string]: int}
+ `,
+ out: `y: _
+`,
+
// }, {
// name: "slice",
// in: `package foo
@@ -135,7 +144,13 @@
if err != nil {
t.Fatal(err)
}
- n := File(f)
+
+ var opts []Option
+ if tc.simplify {
+ opts = append(opts, Simplify())
+ }
+ n := File(f, opts...)
+
b, err := format.Node(n)
if err != nil {
t.Fatal(err)
diff --git a/tools/fix/fixall.go b/tools/fix/fixall.go
index c7a94b0..c2fa2ae 100644
--- a/tools/fix/fixall.go
+++ b/tools/fix/fixall.go
@@ -25,7 +25,7 @@
// Instances modifies all files contained in the given build instances at once.
//
// It also applies fix.File.
-func Instances(a []*build.Instance) errors.Error {
+func Instances(a []*build.Instance, o ...Option) errors.Error {
cwd, _ := os.Getwd()
// Collect all
@@ -34,7 +34,7 @@
cwd: cwd,
}
- p.visitAll(func(f *ast.File) { File(f) })
+ p.visitAll(func(f *ast.File) { File(f, o...) })
return p.err
}