Giter VIP home page Giter VIP logo

ineffassign's People

Contributors

alecthomas avatar alexandear avatar andrew-field avatar davecheney avatar dnephin avatar ericcornelissen avatar estensen avatar gordonklaus avatar jvmatl avatar pmezard avatar rmohr avatar steenzout avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ineffassign's Issues

False positive or explain: could not import C (no metadata for C)

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.

inconsistent behavior with bool initialization

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!

Uncaught ineffectual assignment when using closure

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.

Minor: Support go standard use of ./...

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?

What is causing this ineffassign?

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:

  1. No variable is assigned on that line
  2. The return value is passed straight into a func where it is immediately used

Have I missed something or would this be considered a bug?

Minor: ./* doesn't work on Windows

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.

False positive #2

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
}

Possible false positive

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)

Why is this not reported ?

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.

False Positive when using Defer

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

Why this situation report ineffassign?

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?

False positive: string concatenation

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)
}

(playground)

Uncaught

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.

false positive: assigning to return variable with panic

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

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

False positive

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.

Option (or default) to not recursively check all directories

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.

[Feature request] Add version and expose through flag

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.

False positive #2

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)

Getting warning on err not being used by err is being returned from the function

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.

Ineffassign and declaring variables using the `:=` operator

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 ?

Incorrect ineffectual assignment in switch

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. :) )

Uncaught ineffective assignment

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 { ... }

False positive with slice pointing to an array

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)
	}
}

nil-assigned value does not always need to be used

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.

Build failed due to go tool version mismatch

Appreciate your help with this: (how do I skip this version mismatch)

go test -v

unicode/utf8

compile: version "go1.13.5" does not match go tool version "go1.13.6"

internal/race

compile: version "go1.13.5" does not match go tool version "go1.13.6"

math/bits

compile: version "go1.13.5" does not match go tool version "go1.13.6"

runtime/internal/sys

compile: version "go1.13.5" does not match go tool version "go1.13.6"

unicode

compile: version "go1.13.5" does not match go tool version "go1.13.6"

runtime/internal/atomic

compile: version "go1.13.5" does not match go tool version "go1.13.6"

internal/cpu

compile: version "go1.13.5" does not match go tool version "go1.13.6"

sync/atomic

compile: version "go1.13.5" does not match go tool version "go1.13.6"
FAIL github.com/gordonklaus/ineffassign [build failed]

Missing usage doc

Would you please add some text describing how to use the library?
Thank you!

False Positive question

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.

go generate

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.

False positive

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.

allow ineffectual assignments to pointers

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.

maybePanic panics ;)

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.

Unexpected ineffectual assignment after switch

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

Unexpected ineffectual assignment: type switch

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

Initialization as nil treated as assignment

Problem

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.

Example in the wild

https://github.com/stellar/experimental-payment-channels/pull/204/files/07e7063a43892bd267575c7d6ae9c248424246c0#diff-6922f95bf6260135bad02efc30e1312aed8a596b33fa4871e3d64ccb27ceb73dR897

Reduced example

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.

Not able to detect inherited properties.

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.

vendor directory

if I run

$ ineffassign .

it will also analyze packages in the vendor directory.

if you agree to ignore this I can make a PR.

False positive #3

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")
		}
	}

Allow multiple packages to be passed to program

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.