mirror of
https://github.com/golang/go
synced 2024-09-30 16:18:35 -06:00
internal/lsp/analysis: add simplify-range pass from "gofmt -s"
This is one of the simplifications that "gofmt -s" applies. https://golang.org/cmd/gofmt/#hdr-The_simplify_command A range of the form: for x, _ = range v {...} will be simplified to: for x = range v {...} A range of the form: for _ = range v {...} will be simplified to: for range v {...} Updates golang/go#37221 Change-Id: Ic6babbd0b8ab961ebb4d0d6df72df52d9acde6e7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/223661 Run-TryBot: Rohan Challa <rohan@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
e46a7b92c0
commit
94fe02cb5c
@ -321,6 +321,32 @@ errors is discouraged.
|
||||
|
||||
Default value: `true`.
|
||||
|
||||
### **simplifyrange**
|
||||
|
||||
check for range statement simplifications
|
||||
|
||||
A range of the form:
|
||||
```go
|
||||
for x, _ = range v {...}
|
||||
```
|
||||
will be simplified to:
|
||||
```go
|
||||
for x = range v {...}
|
||||
```
|
||||
|
||||
A range of the form:
|
||||
```go
|
||||
for _ = range v {...}
|
||||
```
|
||||
will be simplified to:
|
||||
```go
|
||||
for range v {...}
|
||||
```
|
||||
|
||||
This is one of the simplifications that "gofmt -s" applies.
|
||||
|
||||
Default value: `true`.
|
||||
|
||||
### **sortslice**
|
||||
|
||||
check the argument type of sort.Slice
|
||||
|
114
internal/lsp/analysis/simplifyrange/simplifyrange.go
Normal file
114
internal/lsp/analysis/simplifyrange/simplifyrange.go
Normal file
@ -0,0 +1,114 @@
|
||||
// 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 simplifyrange defines an Analyzer that simplifies range statements.
|
||||
// https://golang.org/cmd/gofmt/#hdr-The_simplify_command
|
||||
// https://github.com/golang/go/blob/master/src/cmd/gofmt/simplify.go
|
||||
package simplifyrange
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
|
||||
"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 range statement simplifications
|
||||
|
||||
A range of the form:
|
||||
for x, _ = range v {...}
|
||||
will be simplified to:
|
||||
for x = range v {...}
|
||||
|
||||
A range of the form:
|
||||
for _ = range v {...}
|
||||
will be simplified to:
|
||||
for range v {...}
|
||||
|
||||
This is one of the simplifications that "gofmt -s" applies.`
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "simplifyrange",
|
||||
Doc: Doc,
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (interface{}, error) {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.RangeStmt)(nil),
|
||||
}
|
||||
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||
stmt := n.(*ast.RangeStmt)
|
||||
end := newlineIndex(pass.Fset, stmt)
|
||||
var old ast.Expr
|
||||
// Range statements of the form: for i, _ := range x {}
|
||||
if isBlank(stmt.Value) {
|
||||
old = stmt.Value
|
||||
defer func() {
|
||||
stmt.Value = old
|
||||
}()
|
||||
stmt.Value = nil
|
||||
}
|
||||
// Range statements of the form: for _ := range x {}
|
||||
if isBlank(stmt.Key) && stmt.Value == nil {
|
||||
old = stmt.Key
|
||||
defer func() {
|
||||
stmt.Key = old
|
||||
}()
|
||||
stmt.Key = nil
|
||||
}
|
||||
// Return early if neither if condition is met.
|
||||
if old == nil {
|
||||
return
|
||||
}
|
||||
pass.Report(analysis.Diagnostic{
|
||||
Pos: old.Pos(),
|
||||
End: old.End(),
|
||||
Message: "simplify range expression",
|
||||
SuggestedFixes: suggestedFixes(pass.Fset, stmt, end),
|
||||
})
|
||||
})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func suggestedFixes(fset *token.FileSet, rng *ast.RangeStmt, end token.Pos) []analysis.SuggestedFix {
|
||||
var b bytes.Buffer
|
||||
printer.Fprint(&b, fset, rng)
|
||||
stmt := b.Bytes()
|
||||
index := bytes.Index(stmt, []byte("\n"))
|
||||
// If there is a new line character, then don't replace the body.
|
||||
if index != -1 {
|
||||
stmt = stmt[:index]
|
||||
}
|
||||
return []analysis.SuggestedFix{{
|
||||
Message: "Remove empty value",
|
||||
TextEdits: []analysis.TextEdit{{
|
||||
Pos: rng.Pos(),
|
||||
End: end,
|
||||
NewText: stmt[:index],
|
||||
}},
|
||||
}}
|
||||
}
|
||||
|
||||
func newlineIndex(fset *token.FileSet, rng *ast.RangeStmt) token.Pos {
|
||||
var b bytes.Buffer
|
||||
printer.Fprint(&b, fset, rng)
|
||||
contents := b.Bytes()
|
||||
index := bytes.Index(contents, []byte("\n"))
|
||||
if index == -1 {
|
||||
return rng.End()
|
||||
}
|
||||
return rng.Pos() + token.Pos(index)
|
||||
}
|
||||
|
||||
func isBlank(x ast.Expr) bool {
|
||||
ident, ok := x.(*ast.Ident)
|
||||
return ok && ident.Name == "_"
|
||||
}
|
17
internal/lsp/analysis/simplifyrange/simplifyrange_test.go
Normal file
17
internal/lsp/analysis/simplifyrange/simplifyrange_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 simplifyrange_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
"golang.org/x/tools/internal/lsp/analysis/simplifyrange"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
testdata := analysistest.TestData()
|
||||
analysistest.RunWithSuggestedFixes(t, testdata, simplifyrange.Analyzer, "a")
|
||||
}
|
16
internal/lsp/analysis/simplifyrange/testdata/src/a/a.go
vendored
Normal file
16
internal/lsp/analysis/simplifyrange/testdata/src/a/a.go
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// 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
|
||||
|
||||
import "log"
|
||||
|
||||
func m() {
|
||||
maps := make(map[string]string)
|
||||
for k, _ := range maps { // want "simplify range expression"
|
||||
log.Println(k)
|
||||
}
|
||||
for _ = range maps { // want "simplify range expression"
|
||||
}
|
||||
}
|
16
internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden
vendored
Normal file
16
internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// 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
|
||||
|
||||
import "log"
|
||||
|
||||
func m() {
|
||||
maps := make(map[string]string)
|
||||
for k := range maps { // want "simplify range expression"
|
||||
log.Println(k)
|
||||
}
|
||||
for range maps { // want "simplify range expression"
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ import (
|
||||
"golang.org/x/tools/go/analysis/passes/unreachable"
|
||||
"golang.org/x/tools/go/analysis/passes/unsafeptr"
|
||||
"golang.org/x/tools/go/analysis/passes/unusedresult"
|
||||
"golang.org/x/tools/internal/lsp/analysis/simplifyrange"
|
||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||
"golang.org/x/tools/internal/lsp/diff"
|
||||
"golang.org/x/tools/internal/lsp/diff/myers"
|
||||
@ -511,5 +512,6 @@ func defaultAnalyzers() map[string]Analyzer {
|
||||
testinggoroutine.Analyzer.Name: {Analyzer: testinggoroutine.Analyzer, Enabled: true},
|
||||
|
||||
// gofmt -s suite:
|
||||
simplifyrange.Analyzer.Name: {Analyzer: simplifyrange.Analyzer, Enabled: true, HighConfidence: true},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user