8000 Fix SA4026 fixes for math imports by dajiaohuang · Pull Request #1768 · dominikh/go-tools · GitHub
[go: up one dir, main page]

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 44 additions & 5 deletions staticcheck/sa4026/sa4026.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package sa4026

import (
"fmt"
"go/ast"
"go/types"
"strconv"

"honnef.co/go/tools/analysis/code"
"honnef.co/go/tools/analysis/edit"
Expand Down Expand Up @@ -53,26 +55,63 @@ var negativeZeroFloatQ = pattern.MustParse(`
(UnaryExpr "-" lit@(BasicLit "INT" "0"))))`)

func run(pass *analysis.Pass) (any, error) {
mathQualifier := func(node ast.Node) string {
for _, file := range pass.Files {
if node.Pos() < file.Pos() || node.Pos() > file.End() {
continue
}
for _, spec := range file.Imports {
path, err := strconv.Unquote(spec.Path.Value)
if err != nil || path != "math" {
continue
}
var pkgName *types.PkgName
if spec.Name != nil {
pkgName, _ = pass.TypesInfo.Defs[spec.Name].(*types.PkgName)
} else {
pkgName, _ = pass.TypesInfo.Implicits[spec].(*types.PkgName)
}
if pkgName != nil && pkgName.Name() != "." && pkgName.Name() != "_" {
scope := pass.TypesInfo.Scopes[file].Innermost(node.Pos())
if scope != nil {
_, obj := scope.LookupParent(pkgName.Name(), node.Pos())
if obj == pkgName {
return pkgName.Name()
}
}
}
}
}
return ""
}
for node, m := range code.Matches(pass, negativeZeroFloatQ) {
mathName := mathQualifier(node)
if conv, ok := m.State["conv"].(*types.TypeName); ok {
var replacement string
// TODO(dh): how does this handle type aliases?
if conv.Name() == "float32" {
replacement = `float32(math.Copysign(0, -1))`
replacement = fmt.Sprintf(`float32(%s.Copysign(0, -1))`, mathName)
} else {
replacement = `math.Copysign(0, -1)`
replacement = fmt.Sprintf(`%s.Copysign(0, -1)`, mathName)
}
var opts []report.Option
if mathName != "" {
opts = append(opts, report.Fixes(edit.Fix("Use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement))))
}
report.Report(pass, node,
fmt.Sprintf("in Go, the floating-point expression '%s' is the same as '%s(%s)', it does not produce a negative zero",
report.Render(pass, node),
conv.Name(),
report.Render(pass, m.State["lit"])),
report.Fixes(edit.Fix("Use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement))))
opts...)
} else {
const replacement = `math.Copysign(0, -1)`
var opts []report.Option
if mathName != "" {
opts = append(opts, report.Fixes(edit.Fix("Use math.Copysign to create negative zero", edit.ReplaceWithString(node, fmt.Sprintf(`%s.Copysign(0, -1)`, mathName)))))
}
report.Report(pass, node,
"in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero",
report.Fixes(edit.Fix("Use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement))))
opts...)
}
}
return nil, nil
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package pkg

import m "math"

const x = 0.0

func fn() {
_ = m.Copysign
_ = -0.0 //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float32(-0.0) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float64(-0.0) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package pkg

import m "math"

const x = 0.0

func fn() {
_ = math.Copysign(0, -1) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float32(math.Copysign(0, -1)) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float64(math.Copysign(0, -1)) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float32(math.Copysign(0, -1)) //@ diag(`in Go, the floating-point expressio 8000 n '-float32(0)' is the same as 'float32(0)', it does not produce a negative zero`)
_ = math.Copysign(0, -1) //@ diag(`in Go, the floating-point expression '-float64(0)' is the same as 'float64(0)', it does not produce a negative zero`)
_ = float32(math.Copysign(0, -1)) //@ diag(`in Go, the floating-point expression '-float32(0.0)' is the same as 'float32(0.0)', it does not produce a negative zero`)
_ = math.Copysign(0, -1) //@ diag(`in Go, the floating-point expression '-float64(0.0)' is the same as 'float64(0.0)', it does not produce a negative zero`)
_ = m.Copysign
_ = m.Copysign(0, -1) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float32(m.Copysign(0, -1)) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float64(m.Copysign(0, -1)) //@ diag(`in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero`)
_ = float32(m.Copysign(0, -1)) //@ diag(`in Go, the floating-point expression '-float32(0)' is the same as 'float32(0)', it does not produce a negative zero`)
_ = m.Copysign(0, -1) //@ diag(`in Go, the floating-point expression '-float64(0)' is the same as 'float64(0)', it does not produce a negative zero`)
_ = float32(m.Copysign(0, -1)) //@ diag(`in Go, the floating-point expression '-float32(0.0)' is the same as 'float32(0.0)', it does not produce a negative zero`)
_ = m.Copysign(0, -1) //@ diag(`in Go, the floating-point expression '-float64(0.0)' is the same as 'float64(0.0)', it does not produce a negative zero`)

// intentionally not flagged
_ = -x
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pkg

import m "math"

var _ = m.Copysign
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pkg

import m "math"

var _ = m.Copysign
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package pkg

func other() {
_ = -0.0 //@ diag(`does not produce a negative zero`)
_ = float32(-0) //@ diag(`does not produce a negative zero`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package pkg

func other() {
_ = -0.0 //@ diag(`does not produce a negative zero`)
_ = float32(-0) //@ diag(`does not produce a negative zero`)
}
12 changes: 12 additions & 0 deletions staticcheck/sa4026/testdata/go1.0/CheckNegativeZeroScope/shadow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package pkg

import m "math"

var _ = m.Copysign

func shadow() {
m := 1
_ = m
_ = -0.0 //@ diag(`does not produce a negative zero`)
_ = float32(-0) //@ diag(`does not produce a negative zero`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package pkg

import m "math"

var _ = m.Copysign

func shadow() {
m := 1
_ = m
_ = -0.0 //@ diag(`does not produce a negative zero`)
_ = float32(-0) //@ diag(`does not produce a negative zero`)
}
0