Skip to content

Commit

Permalink
fix: fix imports
Browse files Browse the repository at this point in the history
Fixes #14
  • Loading branch information
catenacyber committed Nov 13, 2023
1 parent 838fa0d commit b5358a6
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 2 deletions.
143 changes: 143 additions & 0 deletions analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"go/format"
"go/token"
"go/types"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -58,6 +59,8 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
if fmtSprintfObj == nil && fmtSprintObj == nil && fmtErrorfObj == nil {
return nil, nil
}
removedFmtUsages := make(map[string]int)
neededPackages := make(map[string]map[string]bool)

insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
Expand Down Expand Up @@ -129,7 +132,14 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
var d *analysis.Diagnostic
switch {
case isBasicType(valueType, types.String) && oneOf(verb, "%v", "%s"):
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
if fn == "fmt.Errorf" {
neededPackages[fname]["errors"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand Down Expand Up @@ -166,6 +176,8 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
// known false positive if this error is nil
// fmt.Sprint(nil) does not panic like nil.Error() does
errMethodCall := formatNode(pass.Fset, value) + ".Error()"
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -183,6 +195,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
}

case isBasicType(valueType, types.Bool) && oneOf(verb, "%v", "%t"):
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -205,6 +224,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
return
}

fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["encoding/hex"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -228,6 +254,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
},
}
case isSlice && isBasicType(s.Elem(), types.Uint8) && oneOf(verb, "%x"):
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["encoding/hex"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -245,6 +278,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
}

case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d") && n.intConv:
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -268,6 +308,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
},
}
case isBasicType(valueType, types.Int) && oneOf(verb, "%v", "%d"):
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -284,6 +331,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
},
}
case isBasicType(valueType, types.Int64) && oneOf(verb, "%v", "%d"):
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand Down Expand Up @@ -312,6 +366,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
if verb == "%x" {
base = []byte("), 16")
}
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand Down Expand Up @@ -339,6 +400,13 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
if verb == "%x" {
base = []byte(", 16")
}
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
_, ok := neededPackages[fname]
if !ok {
neededPackages[fname] = make(map[string]bool)
}
neededPackages[fname]["strconv"] = true
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand Down Expand Up @@ -368,6 +436,8 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
} else {
fix = formatNode(pass.Fset, value) + "+" + strconv.Quote(verb[2:])
}
fname := pass.Fset.File(call.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] + 1
d = &analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
Expand All @@ -391,6 +461,79 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
}
})

if len(removedFmtUsages) > 0 {
for _, pkg := range pass.Pkg.Imports() {
if pkg.Path() == "fmt" {
insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter = []ast.Node{
(*ast.SelectorExpr)(nil),
}
insp.Preorder(nodeFilter, func(node ast.Node) {
selec := node.(*ast.SelectorExpr)
selecok, ok := selec.X.(*ast.Ident)
if ok {
pkgname, ok := pass.TypesInfo.ObjectOf(selecok).(*types.PkgName)
if ok && pkgname.Name() == pkg.Name() {
fname := pass.Fset.File(pkgname.Pos()).Name()
removedFmtUsages[fname] = removedFmtUsages[fname] - 1
}
}
})
} else if pkg.Path() == "errors" || pkg.Path() == "strconv" || pkg.Path() == "encoding/hex" {
insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter = []ast.Node{
(*ast.ImportSpec)(nil),
}
insp.Preorder(nodeFilter, func(node ast.Node) {
gd := node.(*ast.ImportSpec)
if gd.Path.Value == strconv.Quote(pkg.Path()) {
fname := pass.Fset.File(gd.Pos()).Name()
_, ok := neededPackages[fname]
if ok {
delete(neededPackages[fname], pkg.Path())
}
}
})
}
}
insp = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter = []ast.Node{
(*ast.ImportSpec)(nil),
}
insp.Preorder(nodeFilter, func(node ast.Node) {
gd := node.(*ast.ImportSpec)
if gd.Path.Value == `"fmt"` {
fix := ""
fname := pass.Fset.File(gd.Pos()).Name()
if removedFmtUsages[fname] < 0 {
fix = fix + `"fmt"`
}
keys := make([]string, 0, len(neededPackages[fname]))
for k := range neededPackages[fname] {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fix = fix + "\n\t\"" + k + `"`
}
pass.Report(analysis.Diagnostic{
Pos: gd.Pos(),
End: gd.End(),
Message: "Fix imports",
SuggestedFixes: []analysis.SuggestedFix{
{
Message: "Fix imports",
TextEdits: []analysis.TextEdit{{
Pos: gd.Pos(),
End: gd.End(),
NewText: []byte(fix),
}},
},
}})
}
})
}

return nil, nil
}

Expand Down
2 changes: 1 addition & 1 deletion analyzer/testdata/src/noconv/p.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package noconv

import (
"errors"
"fmt"
"fmt" // want "Fix imports"
"os"
)

Expand Down
1 change: 1 addition & 0 deletions analyzer/testdata/src/noconv/p.go.golden
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"strconv" // want "Fix imports"
)

var errSentinel = errors.New("connection refused")
Expand Down
2 changes: 1 addition & 1 deletion analyzer/testdata/src/p/p.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package p

import (
"errors"
"fmt"
"fmt" // want "Fix imports"
"io"
"log"
"net/url"
Expand Down
2 changes: 2 additions & 0 deletions analyzer/testdata/src/p/p.go.golden
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package p

import (
"encoding/hex"
"errors"
"fmt"
"io"
"log"
"net/url"
"os"
"strconv" // want "Fix imports"
"time"
)

Expand Down

0 comments on commit b5358a6

Please sign in to comment.