gordonklaus / ineffassign Goto Github PK
View Code? Open in Web Editor NEWDetect ineffectual assignments in Go code.
License: MIT License
Detect ineffectual assignments in Go code.
License: MIT License
Hi, and first thank you for this program.
I have run a Go Report on one of my project, and your program is outputting the following warning:
btrfs-diff-go/pkg/btrfs-diff.go
Line 16: warning: could not import C (no metadata for C) (ineffassign)
It is related to the following line :
package btrfsdiff
// We get the constants from this header.
// #include <btrfs/send.h>
// #include <btrfs/send-utils.h>
// #include <btrfs/ioctl.h>
// #cgo LDFLAGS: -lbtrfs
import "C"
And then the C
import is used like in the following lines :
var commandsDefs *[C.__BTRFS_SEND_C_MAX]commandType = initCommandsDefinitions()
Can you explain to me why the warning, or try to fix it, if it is a false positive.
Thank you in advance.
If I can be of any help, let me know.
While scanning the Go source, this tool reports the following line as an ineffectual assignment to p
:
https://github.com/golang/go/blob/35bb62e60a7779ff82c3067903b3306ff8666471/src/cmd/internal/obj/wasm/wasmobj.go#L221
Obviously, this is not the case and removing that line causes incorrect behaviour (and might even be dangerous).
Full warning:
cmd/internal/obj/wasm/wasmobj.go:225:3:warning: ineffectual assignment to p (ineffassign)
This tool has allowed me to slay many a bug today. Thank you!!!
I also noticed this inconsistent behavior.
package main
import "fmt"
func main() {
s := ""
s = "hello"
fmt.Println("s:", s)
n := 0
n = 42
fmt.Println("n:", n)
b := false
b = true
fmt.Println("b:", b)
}
I can init and update s
and n
as expected, but I'm getting ineffectual assignment to b
.
I am running go1.12.5.
Thanks!
Hi there!
First of all, thanks for creating this awesome linter! It has caught many bugs in our code.
A short while ago, I ran into an issue where an ineffectual assignment was only caught during a code review because the linter did not catch it. So I was wondering whether this is a known false-negative case and whether it can be fixed.
The case has to do with the use of closures. I have recreated three scenarios as tests for testdata.go
.
Cases where the ineffectual assignment is not detected:
func _() {
x := 0
func() {
x = 0
}()
x = 0 //x
x = 0
}
func _() {
x := 0
_ = func() {
x = 0
}
x = 0 //x
x = 0
}
func _() {
x := 0
x = 0 //x
x = 0
_ = func() {
x = 0
_ = x
}
_ = x
}
Case where it is correctly detected:
func _() {
x := 0
_ = func() {
x := 0
_ = x
}
x = 0 //x
x = 0
_ = x
}
As you can see, if a closure uses a variable, the linter then does not detect any ineffectual assignments for that variable. To be clear, it is not about whether the assignment was ineffectual because of what happens within the closure (I can imagine that that is tricky if not impossible to detect). In all of the three missed cases, the ineffectual assignment is directly followed by another assignment.
I'd love to hear if there is anything that can be done about this.
Most go tools support the use of ./... to mean scan from the current directory down as far as you can go. However, ineffassign responds with this: "app/dir/...: no such file or directory"
So instead I had to use ./* which seems to work fine by the way. However, for consistency with other go tools can you add support for ./... too?
Hi there,
I can see in my goreportcard result that I have an ineffassign: https://goreportcard.com/report/github.com/TomWright/dasel
It's highlighting line 281 (line 2 in this snippet):
cmd.AddCommand(
putStringCommand(),
putBoolCommand(),
putIntCommand(),
putObjectCommand(),
putDocumentCommand(),
)
From the README:
An assignment is ineffectual if the variable assigned is not thereafter used.
I don't understand why this line has been highlighted since:
Have I missed something or would this be considered a bug?
The usage example in the README says you can use ineffassign ./*
to analyze the current directory recursively. However, this does not seem to work on Windows, and using ineffassign ./
instead should always work to recursively analyze the current working directory.
This finds a false positive on line 25:
// +build ignore
package main
import (
"math"
"math/rand"
)
func main() {
const tiny = 1e-30
t := 0
f := t
if f == 0 {
f = tiny
}
C := f
D := 0.0
delta := 0.0
for i := 0; i < math.MaxInt64; i++ {
t = rand.Intn()
D = t.B + t.A*D
if D == 0 {
D = tiny
}
C = t.B + t.A/C
if C == 0 {
C = tiny
}
D = 1 / D
delta = C * D
f = f * delta
if math.Abs(delta-1) <= eps {
break
}
}
return f
}
package main
type A struct {
S string
}
func main() {
aList := []A{
{S: "Foo"},
{S: "Bar"},
}
var result *A
for _, i := range aList {
if i.S == "foobar" {
result = &i
break
}
}
if result == nil {
vsf := A{S: "baz"}
result = &vsf
}
}
Reported error:
main.go:23:3: ineffectual assignment to `result` (ineffassign)
Let's consider the code below:
package main
import "fmt"
type inner struct {
s string
}
type outer struct {
inner []inner
}
func main() {
o := outer{
inner: []inner{{
s: "a",
}},
}
for _, i := range o.inner {
i.s = "b"
}
fmt.Println(o)
}
Shouldn't this code be reported ?
i.s = "b"
will have no effect here.
Example Code:
package main
import "fmt"
func main() {
ok := true
defer fmt.Println(ok)
err := someOperation()
if err != nil {
ok = false
return
}
}
func someOperation() error {
return fmt.Errorf("Oh no!")
}
Running ineffassign
returns ineffectual assignment to ok
I have codes like this
format = skipWhiteSpace(format)
for token, formatRemain, succ := getFormatToken(format); len(token) != 0; format = formatRemain {
if !succ {
isDuration, isDate = false, false
break
}
if _, ok := durationTokens[token]; ok {
isDuration = true
} else if _, ok := dateTokens[token]; ok {
isDate = true
}
if isDuration && isDate {
break
}
token, formatRemain, succ = getFormatToken(format)
}
return
}
And ineffassign tell me No.2 line warning: ineffectual assignment to formatRemain
.
But I think this variable I have already used.
I was wondering if you could tell me what I have done wrong?
Because ineffassign
doesn't consider types in its checks, it makes the mistake of assuming that the +
operator is associative. This is not the case for all types - most notably strings.
Here's an example of a small program that does an assignment that is not ineffectual, but does get flagged as such by ineffassign
:
package main
import (
"fmt"
)
const prefix = `prefix `
func main() {
prefixMe := `a string to prefix`
// the below line is flagged
prefixMe = prefix + prefixMe
fmt.Println(prefixMe)
}
package foo
func foo() {
x := 1
x = 2
return &x
}
The initial assignment is ineffective, but isn't caught here, due to the fact that x
escapes.
example program:
package main
import (
"log"
)
func main() {
out := func() (ok bool) {
ok = true
defer func() {
if r := recover(); r != nil {
log.Println("panic happened!")
}
}()
panic("oh crud")
return false
}()
log.Println(out)
}
ineffassign
prints: ineffectual assignment to ok
but if you remove that assignment (line 9), the program will print false instead of true
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x10c3a5d]
goroutine 1 [running]:
main.(*branchStack).get(0xc420341258, 0x0, 0xc42034c2a0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:512 +0x6d
main.(*builder).Visit(0xc420341200, 0x111a2a0, 0xc4203ea560, 0x1119ce0, 0xc420341200)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:226 +0x15c3
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a2a0, 0xc4203ea560)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:52 +0x66
go/ast.walkStmtList(0x1119ce0, 0xc420341200, 0xc4203ea580, 0x2, 0x2)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:32 +0x81
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a260, 0xc4203e65a0)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:224 +0x1b61
main.(*builder).walk(0xc420341200, 0x111a260, 0xc4203e65a0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:122 +0x5a
main.(*builder).Visit(0xc420341200, 0x111a860, 0xc4203c1d80, 0x0, 0x0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:139 +0x236f
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a860, 0xc4203c1d80)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:52 +0x66
go/ast.walkStmtList(0x1119ce0, 0xc420341200, 0xc42033b300, 0x9, 0x10)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:32 +0x81
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a260, 0xc4203e65d0)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:224 +0x1b61
main.(*builder).walk(0xc420341200, 0x111a260, 0xc4203e65d0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:122 +0x5a
main.(*builder).fun(0xc420341200, 0xc4203ea820, 0xc4203e65d0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:379 +0x1aa
main.(*builder).Visit(0xc420341200, 0x111a6e0, 0xc4203e6600, 0x0, 0x0)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:130 +0xc84
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a6e0, 0xc4203e6600)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:52 +0x66
go/ast.walkDeclList(0x1119ce0, 0xc420341200, 0xc4203b6580, 0x7, 0x8)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:38 +0x81
go/ast.Walk(0x1119ce0, 0xc420341200, 0x111a660, 0xc4203b6780)
/usr/local/Cellar/go/1.10.2/libexec/src/go/ast/walk.go:353 +0x2650
main.(*builder).walk(0xc420341200, 0x111a660, 0xc4203b6780)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:122 +0x5a
main.checkPath(0xc42038eb60, 0x67, 0x3, 0xc42034db01, 0x1063946, 0xc42038ebd0, 0xc42038eb60, 0x67, 0xc42034db50)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:79 +0xfa
main.walkPath.func1(0xc42038eb60, 0x67, 0x111bd60, 0xc42039fee0, 0x0, 0x0, 0xc, 0xc42034dc48)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:61 +0x165
path/filepath.walk(0xc42038eb60, 0x67, 0x111bd60, 0xc42039fee0, 0xc4200a8060, 0x0, 0x0)
/usr/local/Cellar/go/1.10.2/libexec/src/path/filepath/path.go:357 +0x402
path/filepath.walk(0xc42030df80, 0x5a, 0x111bd60, 0xc42039fe10, 0xc4200a8060, 0x0, 0x0)
/usr/local/Cellar/go/1.10.2/libexec/src/path/filepath/path.go:381 +0x2c2
path/filepath.walk(0xc42008e120, 0x50, 0x111bd60, 0xc420096b60, 0xc4200a8060, 0x0, 0x20)
/usr/local/Cellar/go/1.10.2/libexec/src/path/filepath/path.go:381 +0x2c2
path/filepath.Walk(0xc42008e120, 0x50, 0xc4200a8060, 0x50, 0x0)
/usr/local/Cellar/go/1.10.2/libexec/src/path/filepath/path.go:403 +0x106
main.walkPath(0xc42008e120, 0x50, 0xc42008e120)
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:45 +0x9a
main.main()
/Users/aat/.go/src/github.com/alecthomas/gometalinter/_linters/src/github.com/gordonklaus/ineffassign/ineffassign.go:34 +0x7a
Example from my code:
for _, server := range servers {
f := false
if server.State == stateUnconn || server.State == stateFailed {
if f == false {
f = true
vy++
}
Error message:
f assigned and not used (ineffassign)
f has already been assigned in the outer loop so error should not happen when f is set to true.
there is a false report in where it assigns to a receiver
https://github.com/kubernetes/test-infra/blob/master/def/configmap/main.go#L64
func (mkv *multiKeyValue) Set(v string) error {
p := strings.SplitN(v, "=", 2)
if len(p) != 2 {
return fmt.Errorf("%s does not match label=value", v)
}
if mkv == nil {
mkv = &multiKeyValue{
p[0]: p[1],
}
} else {
(*mkv)[p[0]] = p[1]
}
return nil
}
func (f *Foo) Bar() (bzs []Baz, err error) {
if bs, err := ioutil.ReadFile(os.Getenv(bazesPathKey)); err == nil {
// ineffassign claims that this is not used, but it's a return value
err = json.Unmarshal(bs, &bzs)
}
return
}
https://goreportcard.com/report/github.com/tinode/chat
Line 1021: warning: err assigned and not used (ineffassign)
This is the line it complains about:
https://github.com/tinode/chat/blob/master/server/db/rethinkdb/adapter.go#L1021
Thanks.
This is very slow with vendored source trees, and can be easily replicated with find . -type d | xargs ineffassign
. It also makes integrating the tool into an editor likely to be much slower.
Most Go tools allow both: <dir>
will check just that dir and <dir>/...
will recursively check all dirs underneath. This would be ideal.
Hi, it would be useful for debugging if ineffassign was versioned and one could get that version through --version
flag. Right now it's hard to know what version of ineffassign is installed. Ideally one would get the commit of the build but I don't know if that can be done easily and keep the installation through go get
.
While scanning the Go source, this tool reports the following lines as an ineffectual assignment to v:
This is not the case as the code is testing runtime finalizers.
Full warnings:
runtime/mfinal_test.go:60:4:warning: ineffectual assignment to v (ineffassign)
runtime/mfinal_test.go:98:3:warning: ineffectual assignment to v (ineffassign)
and
runtime/stack_test.go:126:4:warning: ineffectual assignment to s (ineffassign)
I noticed the usage here https://goreportcard.com/report/github.com/The-Eye-Team/reddit-dl#ineffassign. In it, I have code very similar to the following..
l := true
if complicatedCondition() {
l = false
}
if anotherComplicatedCondition() {
l = false
}
if l {
// do some code that handles the default case
}
and ineffassign is labeling the l = false
lines as ineffectual assigns. I believe this to be a bug. Conversation welcome :)
Hi, im getting a warning of unused variable: Line 331: warning: err assigned and not used (ineffassign)
Bur error is actually being used, is the return of the function.
here is the code:
resp := friendResp{}
err = json.Unmarshal(body, &resp)
user.Friendship = resp.Friendship
}
}
return err
}
Im using goreportcard.com to run the test. thanks.
I was wondering: ineffassign will flag variable declarations using the :=
declarations like this:
dir := ""
As an ineffectual assignment.
This could be changed to:
var dir string
To make the error go away, but isn't just a case of style preference ?
Case in hand, David Crawshaw (from the Go team) disagrees with this behaviour, see this comment.
Would you consider white-listing this pattern ?
I found a false ineffectual assignment in a case similar to this:
package main
import (
"fmt"
)
func main() {
var a int
switch n := -1; {
case n == -1:
n += 1
fallthrough
case n == 0:
a = 10
}
fmt.Println(a)
}
It says that n += 1
is ineffectual when it is very much effectual. Without it a
is 0
, with it it's 10
.
Same example on go playground here.
(Also, thanks for good linting in general, very useful for catching bugs. :) )
Line https://github.com/ericlagergren/decimal/blob/522450d1e655d86ef13b0bfad42d090a0240ce03/decimal.go#L430 is marked as an ineffectual assign.
package main
import "fmt"
func main() {
var i int
i = 3
i = 5
fmt.Println(i)
}
$ ineffassign main.go
does not produce any results. It should catch that the i = 3
assignment was ineffective (its value was never used).
I created the issue because I discovered an unchecked error in my code because of this pattern, i.e.:
err := someCall()
err = anotherCall()
if err != nil { ... }
This program triggers a false positive reported by ineffassign: main.go:9:3: ineffectual assignment to iv
.
iv
and ivSlice
point to the same data so this is not a ineffective assignment.
package main
import "fmt"
func main() {
var iv [16]byte
ivSlice := iv[:]
for i := range ivSlice {
iv = [16]byte{} // Reset
ivSlice[i] = 'A'
fmt.Printf("%x\n", ivSlice)
}
}
noticed this the other day, and was surprised the linter didn't pick it up:
type X struct {
A int
}
xs := []X{{A:1},{A:2},{A:3}}
for _, x := range xs {
// would expect to see a warning here.
x.A = 5
}
log.Println(xs)
package main
import "fmt"
func main() {
var kvs [][]string
fmt.Println(kvs)
kvs = nil
}
ineffassign ineffassign.go
/home/gyuho/ineffassign.go:8:2: kvs assigned and not used
We assign nil
to kvs
, which is already used in previous line. And the tool assumes it's a new assignment. Could you fix this?
Thanks.
Appreciate your help with this: (how do I skip this version mismatch)
go test -v
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
compile: version "go1.13.5" does not match go tool version "go1.13.6"
FAIL github.com/gordonklaus/ineffassign [build failed]
Prior to the latest version of ineffassign things were working as expected
Using version v0.0.0-20210103220932-664217a59c00 we are seeing:
ineffassign $(find . -name "*.go")
-: named files must all be in one directory; have ./operator/mocks/ and ./operator/test/integ/util/
ineffassign: error during loading
Would you please add some text describing how to use the library?
Thank you!
I have a case where I want to nil a receiver under a certain condition. Let's say to nil/remove the age from a user which I fetched from the database:
type AgeType int
func (a *AgeType) UnmarshalJSON(data []byte) error {
if len(data) == 0 {
a = nil
return nil
}
return nil
}
ineffassign
would identify the a = nil
.
Would there be any way to ignore go generated files.
A developper has not allways the control over these.
Naturally correction to the thing generating the files is a solution but this can take time.
Issue is explained with examples here: golang/go#43565.
Basically: if you are iterating using a variable and assigning its pointer to another thing then the values assigned al point to the last value v
took in the iteration! Very tricky bug!
for _, v := range x {
y = append(y, &v) // y will be a slice of the same pointer! Very likely not what you want
}
Encountered this in some real code. This is the minimal repro:
package main
func main() {
var a, b uint64
for x, y := a, uint64(0); b < 10; b += y {
_ = x
y = 5
}
}
The analysis gives:
main.go:5:9: ineffectual assignment to y
However, without the declaration of y
on that line, the code will not compile. The assignment is necessary to declare y
.
func (s *Token) RPCCreate(req CreationRequest, response *Token) {
response = NewPermanent(req.Application, &req.Permissions, req.Expiration)
}
This triggers an ineffectual assignment warning but it is not. The response is evaluated by the request sender.
Hi, I noticed that ineffassign
panics on the following code snippet
package p
import (
"io"
"io/ioutil"
)
var w = ioutil.Discard
var MyVar MyType
type MyType struct {}
func (m *MyType) DoWith(w io.Writer) {
w.Write([]byte("xyz"))
}
func init() {
MyVar.DoWith(w)
}
Stacktrace
goroutine 1 [running]:
main.(*builder).maybePanic(0xc4200985a0)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:438 +0xe9
main.(*builder).Visit(0xc4200985a0, 0x5983e0, 0xc4200d7ec0, 0x0, 0x597fe0)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:325 +0x29d0
go/ast.Walk(0x5971e0, 0xc4200985a0, 0x5983e0, 0xc4200d7ec0)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:52 +0x66
go/ast.Walk(0x5971e0, 0xc4200985a0, 0x597ca0, 0xc4200cf840)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:102 +0x4a7
go/ast.Walk(0x5971e0, 0xc4200985a0, 0x598620, 0xc4200d7fc0)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:143 +0x15df
main.(*builder).walk(0xc4200985a0, 0x598620, 0xc4200d7fc0)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:122 +0x5a
main.(*builder).Visit(0xc4200985a0, 0x597fe0, 0xc4200cf880, 0x0, 0x0)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:261 +0x163
go/ast.Walk(0x5971e0, 0xc4200985a0, 0x597fe0, 0xc4200cf880)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:52 +0x66
go/ast.walkDeclList(0x5971e0, 0xc4200985a0, 0xc4200cf900, 0x3, 0x4)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:38 +0x81
go/ast.Walk(0x5971e0, 0xc4200985a0, 0x597ea0, 0xc420096d00)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/go/ast/walk.go:353 +0x266f
main.(*builder).walk(0xc4200985a0, 0x597ea0, 0xc420096d00)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:122 +0x5a
main.checkPath(0xc42001bb80, 0x45, 0x50db28, 0x3, 0xc4200cbb01, 0x43bd57, 0x50, 0x4e2c60, 0x1)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:79 +0x12d
main.walkPath.func1(0xc42001bb80, 0x45, 0x599e40, 0xc4200abee0, 0x0, 0x0, 0x0, 0x0)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:61 +0x186
path/filepath.walk(0xc42001bb80, 0x45, 0x599e40, 0xc4200abee0, 0xc42000a0c0, 0x0, 0x0)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/path/filepath/path.go:356 +0x81
path/filepath.walk(0xc42001cd80, 0x37, 0x599e40, 0xc420085520, 0xc42000a0c0, 0x0, 0x0)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/path/filepath/path.go:381 +0x39a
path/filepath.walk(0xc42001c240, 0x33, 0x599e40, 0xc420072750, 0xc42000a0c0, 0x0, 0x20)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/path/filepath/path.go:381 +0x39a
path/filepath.Walk(0xc42001c240, 0x33, 0xc42000a0c0, 0x1, 0xc42001c240)
/home/travis/.gimme/versions/go1.9.2.linux.amd64/src/path/filepath/path.go:403 +0x11d
main.walkPath(0xc42001c240, 0x33, 0xc42001c240)
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:45 +0x9a
main.main()
/home/travis/gopath/src/github.com/gordonklaus/ineffassign/ineffassign.go:34 +0x7a
Looks like a bug to me. It was working (no ineff assignments reported) with previous versions, i.e. commit f4847a1 and earlier.
Any help is appreciated.
Hello!
package main
import "fmt"
func returnFalse() bool {
return false
}
func returnTrue() bool {
return true
}
func main() {
isValid := true
var i interface{} = 100
switch i.(type) {
case int:
isValid = returnFalse()
default:
isValid = returnTrue()
}
if !isValid {
fmt.Println("value changed")
}
}
▶ ineffassign main.go
/Users/anthony/main.go:14:2: ineffectual assignment to isValid
Hello!
package main
import "fmt"
func main() {
var i interface{} = 100
i = "100"
switch i.(type) {
case int:
fmt.Println("int")
default:
fmt.Println("not int")
}
}
$ ineffassign main.go
/Users/anthony/main.go:6:6: ineffectual assignment to i
It appears that ineffassign treats the assign of a nil value that is later replaced without being used a ineffectual assignment, however this is inconsistent with other types, such as bools, and ints, where a default value is allowed.
This issue shows up frequently when defining a pointer variable that will be nil, but then in a block, say inside a for loop or an if, the value will be set.
This errors forces rewriting s := (*S)(nil)
to var s *S
, which is style only.
When I run ineffassign, using golangci-lint, I see this error for the following code:
test.go:8:2: ineffectual assignment to s (ineffassign)
s := (*S)(nil)
^
package main
import "fmt"
type S struct{}
func main() {
s := (*S)(nil)
s = &S{}
fmt.Println(s)
}
Thanks for making ineffassign! It has helped catch plenty of my silly mistakes before anyone else got to see them.
If you have:
package house
type CommonProperties struct {
RoomType string
RoomSize string
}
And then you have:
package kitchen
type Kitchen struct {
house.CommonProperties
Seats int
Stove bool
}
And then in package kitchen you try to do something like:
func (k *Kitchen) Something() {
k.RoomType = "Kitchen"
}
This tool will give an error saying that RoomType is not a valid assignment.
if I run
$ ineffassign .
it will also analyze packages in the vendor
directory.
if you agree to ignore this I can make a PR.
It would be nice to allow to ignore checks by writing comment like:
// ineffassign: ignore
i.e.
res := someFunction() // ineffassign: ignore
The linter complains ineffectual assignment to dataclientUsingSecondarykey
on second assignment of dataclientUsingSecondaryKey = true
. But the variable is being used again later on. Looks like bug?
var dataclientUsingSecondaryKey bool
containerExists, rerr := storagedataclient.ContainerExists(ctx, goal.ContainerName)
if rerr != nil {
dataclientUsingSecondaryKey = true
}
logger.TraceInfof("container '%s' exists: %t", goal.ContainerName, containerExists)
if goal.IsDeleting {
if rerr := storagedataclient.DeleteContainer(ctx, goal.ContainerName); rerr != nil {
if !dataclientUsingSecondaryKey {
dataclientUsingSecondaryKey = true
storagedataclient.DeleteContainer(ctx, goal.ContainerName)
}
}
}
logger.TraceInfof("Delete container '%s' succeeded.", goal.ContainerName)
return retry.Success, nil, nil
}
if rerr := storagedataclient.CreateContainer(ctx, goal.ContainerName, azStorage.ContainerAccessTypePrivate); rerr != nil {
if !dataclientUsingSecondaryKey {
logger.TraceInfof("Creating storagedataclient with secondary key since CreateContainer returned AuthenticationFailed")
}
}
It would be helpful if multiple packages could be provided to ineffassign
for analysis. Most other static Go analysis tools support this behavior as well, so would be great to make this consistent. Happy to open a PR if you think this would be reasonable.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.