mirror of
https://github.com/golang/go
synced 2024-11-18 08:44:43 -07:00
internal/lsp/analysis: add simplify-slice pass from "gofmt -s"
This is one of the simplifications that "gofmt -s" applies. https://golang.org/cmd/gofmt/#hdr-The_simplify_command A slice expression of the form: s[a:len(s)] will be simplified to: s[a:] Updates golang/go#37221 Change-Id: Ibd4dedaadc9b129d5d39524f0c1ccc8a95bf7e0d Reviewed-on: https://go-review.googlesource.com/c/tools/+/223659 Run-TryBot: Rohan Challa <rohan@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
e428a8eca3
commit
5d86d385bf
@ -364,6 +364,23 @@ This is one of the simplifications that "gofmt -s" applies.
|
|||||||
|
|
||||||
Default value: `true`.
|
Default value: `true`.
|
||||||
|
|
||||||
|
### **simplifyslice**
|
||||||
|
|
||||||
|
check for slice simplifications
|
||||||
|
|
||||||
|
A slice expression of the form:
|
||||||
|
```go
|
||||||
|
s[a:len(s)]
|
||||||
|
```
|
||||||
|
will be simplified to:
|
||||||
|
```go
|
||||||
|
s[a:]
|
||||||
|
```
|
||||||
|
|
||||||
|
This is one of the simplifications that "gofmt -s" applies.
|
||||||
|
|
||||||
|
Default value: `true`.
|
||||||
|
|
||||||
### **sortslice**
|
### **sortslice**
|
||||||
|
|
||||||
check the argument type of sort.Slice
|
check the argument type of sort.Slice
|
||||||
|
96
internal/lsp/analysis/simplifyslice/simplifyslice.go
Normal file
96
internal/lsp/analysis/simplifyslice/simplifyslice.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package simplifyslice defines an Analyzer that simplifies slice statements.
|
||||||
|
// https://github.com/golang/go/blob/master/src/cmd/gofmt/simplify.go
|
||||||
|
// https://golang.org/cmd/gofmt/#hdr-The_simplify_command
|
||||||
|
package simplifyslice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/printer"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||||
|
"golang.org/x/tools/go/ast/inspector"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Doc = `check for slice simplifications
|
||||||
|
|
||||||
|
A slice expression of the form:
|
||||||
|
s[a:len(s)]
|
||||||
|
will be simplified to:
|
||||||
|
s[a:]
|
||||||
|
|
||||||
|
This is one of the simplifications that "gofmt -s" applies.`
|
||||||
|
|
||||||
|
var Analyzer = &analysis.Analyzer{
|
||||||
|
Name: "simplifyslice",
|
||||||
|
Doc: Doc,
|
||||||
|
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||||
|
Run: run,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
|
||||||
|
// but we leave them as is since sometimes we want to be very explicit
|
||||||
|
// about the lower bound.
|
||||||
|
// An example where the 0 helps:
|
||||||
|
// x, y, z := b[0:2], b[2:4], b[4:6]
|
||||||
|
// An example where it does not:
|
||||||
|
// x, y := b[:n], b[n:]
|
||||||
|
|
||||||
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||||
|
nodeFilter := []ast.Node{
|
||||||
|
(*ast.SliceExpr)(nil),
|
||||||
|
}
|
||||||
|
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||||
|
expr := n.(*ast.SliceExpr)
|
||||||
|
// - 3-index slices always require the 2nd and 3rd index
|
||||||
|
if expr.Max != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s, ok := expr.X.(*ast.Ident)
|
||||||
|
// the array/slice object is a single, resolved identifier
|
||||||
|
if !ok || s.Obj == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
call, ok := expr.High.(*ast.CallExpr)
|
||||||
|
// the high expression is a function call with a single argument
|
||||||
|
if !ok || len(call.Args) != 1 || call.Ellipsis.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fun, ok := call.Fun.(*ast.Ident)
|
||||||
|
// the function called is "len" and it is not locally defined; and
|
||||||
|
// because we don't have dot imports, it must be the predefined len()
|
||||||
|
if !ok || fun.Name != "len" || fun.Obj != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arg, ok := call.Args[0].(*ast.Ident)
|
||||||
|
// the len argument is the array/slice object
|
||||||
|
if !ok || arg.Obj != s.Obj {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
old := expr.High
|
||||||
|
var b bytes.Buffer
|
||||||
|
printer.Fprint(&b, pass.Fset, old)
|
||||||
|
pass.Report(analysis.Diagnostic{
|
||||||
|
Pos: old.Pos(),
|
||||||
|
End: old.End(),
|
||||||
|
Message: fmt.Sprintf("unneeded: %s", b.String()),
|
||||||
|
SuggestedFixes: []analysis.SuggestedFix{{
|
||||||
|
Message: fmt.Sprintf("Remove '%s'", b.String()),
|
||||||
|
TextEdits: []analysis.TextEdit{{
|
||||||
|
Pos: old.Pos(),
|
||||||
|
End: old.End(),
|
||||||
|
NewText: []byte{},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
expr.High = old
|
||||||
|
})
|
||||||
|
return nil, nil
|
||||||
|
}
|
17
internal/lsp/analysis/simplifyslice/simplifyslice_test.go
Normal file
17
internal/lsp/analysis/simplifyslice/simplifyslice_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package simplifyslice_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis/analysistest"
|
||||||
|
"golang.org/x/tools/internal/lsp/analysis/simplifyslice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test(t *testing.T) {
|
||||||
|
testdata := analysistest.TestData()
|
||||||
|
analysistest.RunWithSuggestedFixes(t, testdata, simplifyslice.Analyzer, "a")
|
||||||
|
}
|
70
internal/lsp/analysis/simplifyslice/testdata/src/a/a.go
vendored
Normal file
70
internal/lsp/analysis/simplifyslice/testdata/src/a/a.go
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
var (
|
||||||
|
a [10]byte
|
||||||
|
b [20]float32
|
||||||
|
s []int
|
||||||
|
t struct {
|
||||||
|
s []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = a[0:]
|
||||||
|
_ = a[1:10]
|
||||||
|
_ = a[2:len(a)] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[3:(len(a))]
|
||||||
|
_ = a[len(a)-1 : len(a)] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[2:len(a):len(a)]
|
||||||
|
|
||||||
|
_ = a[:]
|
||||||
|
_ = a[:10]
|
||||||
|
_ = a[:len(a)] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[:(len(a))]
|
||||||
|
_ = a[:len(a)-1]
|
||||||
|
_ = a[:len(a):len(a)]
|
||||||
|
|
||||||
|
_ = s[0:]
|
||||||
|
_ = s[1:10]
|
||||||
|
_ = s[2:len(s)] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s[3:(len(s))]
|
||||||
|
_ = s[len(a) : len(s)-1]
|
||||||
|
_ = s[0:len(b)]
|
||||||
|
_ = s[2:len(s):len(s)]
|
||||||
|
|
||||||
|
_ = s[:]
|
||||||
|
_ = s[:10]
|
||||||
|
_ = s[:len(s)] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s[:(len(s))]
|
||||||
|
_ = s[:len(s)-1]
|
||||||
|
_ = s[:len(b)]
|
||||||
|
_ = s[:len(s):len(s)]
|
||||||
|
|
||||||
|
_ = t.s[0:]
|
||||||
|
_ = t.s[1:10]
|
||||||
|
_ = t.s[2:len(t.s)]
|
||||||
|
_ = t.s[3:(len(t.s))]
|
||||||
|
_ = t.s[len(a) : len(t.s)-1]
|
||||||
|
_ = t.s[0:len(b)]
|
||||||
|
_ = t.s[2:len(t.s):len(t.s)]
|
||||||
|
|
||||||
|
_ = t.s[:]
|
||||||
|
_ = t.s[:10]
|
||||||
|
_ = t.s[:len(t.s)]
|
||||||
|
_ = t.s[:(len(t.s))]
|
||||||
|
_ = t.s[:len(t.s)-1]
|
||||||
|
_ = t.s[:len(b)]
|
||||||
|
_ = t.s[:len(t.s):len(t.s)]
|
||||||
|
)
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
s := s[0:len(s)] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func m() {
|
||||||
|
maps := []int{}
|
||||||
|
_ = maps[1:len(maps)] // want "unneeded: len\\(maps\\)"
|
||||||
|
}
|
70
internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden
vendored
Normal file
70
internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
var (
|
||||||
|
a [10]byte
|
||||||
|
b [20]float32
|
||||||
|
s []int
|
||||||
|
t struct {
|
||||||
|
s []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = a[0:]
|
||||||
|
_ = a[1:10]
|
||||||
|
_ = a[2:] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[3:(len(a))]
|
||||||
|
_ = a[len(a)-1:] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[2:len(a):len(a)]
|
||||||
|
|
||||||
|
_ = a[:]
|
||||||
|
_ = a[:10]
|
||||||
|
_ = a[:] // want "unneeded: len\\(a\\)"
|
||||||
|
_ = a[:(len(a))]
|
||||||
|
_ = a[:len(a)-1]
|
||||||
|
_ = a[:len(a):len(a)]
|
||||||
|
|
||||||
|
_ = s[0:]
|
||||||
|
_ = s[1:10]
|
||||||
|
_ = s[2:] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s[3:(len(s))]
|
||||||
|
_ = s[len(a) : len(s)-1]
|
||||||
|
_ = s[0:len(b)]
|
||||||
|
_ = s[2:len(s):len(s)]
|
||||||
|
|
||||||
|
_ = s[:]
|
||||||
|
_ = s[:10]
|
||||||
|
_ = s[:] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s[:(len(s))]
|
||||||
|
_ = s[:len(s)-1]
|
||||||
|
_ = s[:len(b)]
|
||||||
|
_ = s[:len(s):len(s)]
|
||||||
|
|
||||||
|
_ = t.s[0:]
|
||||||
|
_ = t.s[1:10]
|
||||||
|
_ = t.s[2:len(t.s)]
|
||||||
|
_ = t.s[3:(len(t.s))]
|
||||||
|
_ = t.s[len(a) : len(t.s)-1]
|
||||||
|
_ = t.s[0:len(b)]
|
||||||
|
_ = t.s[2:len(t.s):len(t.s)]
|
||||||
|
|
||||||
|
_ = t.s[:]
|
||||||
|
_ = t.s[:10]
|
||||||
|
_ = t.s[:len(t.s)]
|
||||||
|
_ = t.s[:(len(t.s))]
|
||||||
|
_ = t.s[:len(t.s)-1]
|
||||||
|
_ = t.s[:len(b)]
|
||||||
|
_ = t.s[:len(t.s):len(t.s)]
|
||||||
|
)
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
s := s[0:] // want "unneeded: len\\(s\\)"
|
||||||
|
_ = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func m() {
|
||||||
|
maps := []int{}
|
||||||
|
_ = maps[1:] // want "unneeded: len\\(maps\\)"
|
||||||
|
}
|
@ -38,6 +38,7 @@ import (
|
|||||||
"golang.org/x/tools/go/analysis/passes/unusedresult"
|
"golang.org/x/tools/go/analysis/passes/unusedresult"
|
||||||
"golang.org/x/tools/internal/lsp/analysis/simplifycompositelit"
|
"golang.org/x/tools/internal/lsp/analysis/simplifycompositelit"
|
||||||
"golang.org/x/tools/internal/lsp/analysis/simplifyrange"
|
"golang.org/x/tools/internal/lsp/analysis/simplifyrange"
|
||||||
|
"golang.org/x/tools/internal/lsp/analysis/simplifyslice"
|
||||||
"golang.org/x/tools/internal/lsp/analysis/unusedparams"
|
"golang.org/x/tools/internal/lsp/analysis/unusedparams"
|
||||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||||
"golang.org/x/tools/internal/lsp/diff"
|
"golang.org/x/tools/internal/lsp/diff"
|
||||||
@ -517,5 +518,6 @@ func defaultAnalyzers() map[string]Analyzer {
|
|||||||
// gofmt -s suite:
|
// gofmt -s suite:
|
||||||
simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, Enabled: true, HighConfidence: true},
|
simplifycompositelit.Analyzer.Name: {Analyzer: simplifycompositelit.Analyzer, Enabled: true, HighConfidence: true},
|
||||||
simplifyrange.Analyzer.Name: {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
|
simplifyrange.Analyzer.Name: {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
|
||||||
|
simplifyslice.Analyzer.Name: {Analyzer: simplifyslice.Analyzer, Enabled: true, HighConfidence: true},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user