golang.org/x/tools/gopls@v0.15.3/internal/analysis/simplifyslice/simplifyslice.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package simplifyslice 6 7 import ( 8 "bytes" 9 _ "embed" 10 "fmt" 11 "go/ast" 12 "go/printer" 13 14 "golang.org/x/tools/go/analysis" 15 "golang.org/x/tools/go/analysis/passes/inspect" 16 "golang.org/x/tools/go/ast/inspector" 17 "golang.org/x/tools/internal/analysisinternal" 18 ) 19 20 //go:embed doc.go 21 var doc string 22 23 var Analyzer = &analysis.Analyzer{ 24 Name: "simplifyslice", 25 Doc: analysisinternal.MustExtractDoc(doc, "simplifyslice"), 26 Requires: []*analysis.Analyzer{inspect.Analyzer}, 27 Run: run, 28 URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifyslice", 29 } 30 31 // Note: We could also simplify slice expressions of the form s[0:b] to s[:b] 32 // but we leave them as is since sometimes we want to be very explicit 33 // about the lower bound. 34 // An example where the 0 helps: 35 // x, y, z := b[0:2], b[2:4], b[4:6] 36 // An example where it does not: 37 // x, y := b[:n], b[n:] 38 39 func run(pass *analysis.Pass) (interface{}, error) { 40 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 41 nodeFilter := []ast.Node{ 42 (*ast.SliceExpr)(nil), 43 } 44 inspect.Preorder(nodeFilter, func(n ast.Node) { 45 expr := n.(*ast.SliceExpr) 46 // - 3-index slices always require the 2nd and 3rd index 47 if expr.Max != nil { 48 return 49 } 50 s, ok := expr.X.(*ast.Ident) 51 // the array/slice object is a single, resolved identifier 52 if !ok || s.Obj == nil { 53 return 54 } 55 call, ok := expr.High.(*ast.CallExpr) 56 // the high expression is a function call with a single argument 57 if !ok || len(call.Args) != 1 || call.Ellipsis.IsValid() { 58 return 59 } 60 fun, ok := call.Fun.(*ast.Ident) 61 // the function called is "len" and it is not locally defined; and 62 // because we don't have dot imports, it must be the predefined len() 63 if !ok || fun.Name != "len" || fun.Obj != nil { 64 return 65 } 66 arg, ok := call.Args[0].(*ast.Ident) 67 // the len argument is the array/slice object 68 if !ok || arg.Obj != s.Obj { 69 return 70 } 71 var b bytes.Buffer 72 printer.Fprint(&b, pass.Fset, expr.High) 73 pass.Report(analysis.Diagnostic{ 74 Pos: expr.High.Pos(), 75 End: expr.High.End(), 76 Message: fmt.Sprintf("unneeded: %s", b.String()), 77 SuggestedFixes: []analysis.SuggestedFix{{ 78 Message: fmt.Sprintf("Remove '%s'", b.String()), 79 TextEdits: []analysis.TextEdit{{ 80 Pos: expr.High.Pos(), 81 End: expr.High.End(), 82 NewText: []byte{}, 83 }}, 84 }}, 85 }) 86 }) 87 return nil, nil 88 }