Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect return parameters that are just a receiving parameter #18

Closed
mvdan opened this issue Aug 16, 2017 · 7 comments
Closed

Detect return parameters that are just a receiving parameter #18

mvdan opened this issue Aug 16, 2017 · 7 comments

Comments

@mvdan
Copy link
Owner

mvdan commented Aug 16, 2017

In other words, when the values must already be in the hands of the caller.

For example, the receiver:

func (f *foo) bar() foo {
    doWork()
    return f
}

A receiver's field:

func (f *foo) bar() int {
    doWork()
    return f.intField
}

A received parameter:

func bar(n int) int {
    doWork()
    return n
}

Of course, the value must not have been modified under any of those cases.

@mvdan
Copy link
Owner Author

mvdan commented Aug 16, 2017

Hmm, the first type could be problematic with projects that use the idiom of chaining methods, like in f.bar().etc(). We probably want to leave it out for now.

@kevinburke
Copy link

I could imagine a situation where I define a method in anticipation of it changing later, say,

func (u *User) Suspended() bool {
    return u.Canceled
}

where later it might turn into (once a new field gets added):

func (u *User) Suspended() bool {
    return u.Canceled && !u.SuspendedAt.IsZero()
}

The first way I'd have to go find every place Canceled was called and decide whether I really meant Suspended and change it.

@mvdan
Copy link
Owner Author

mvdan commented Aug 28, 2017

You're right, fields is also problematic.

I think I'll just go for return parameters that are always one of the receiving parameters (minus method receivers).

@tehsphinx
Copy link

Also consider this case:

func foo (n *someStruct) *someStruct {
    n.Val1 = "bar"
    return n
}

The return value is not necessary.

@mvdan
Copy link
Owner Author

mvdan commented Oct 28, 2017

@tehsphinx ah yes, modifying what's behind a pointer as long as the pointer itself is not modified means that the return value can still be unnecessary. Thanks for pointing that out.

@mvdan mvdan closed this as completed in f41970f Nov 12, 2017
@mvdan
Copy link
Owner Author

mvdan commented Nov 12, 2017

Implemented this, but starting to have some doubts that it's actually useful. On the latest tip, these are the newly found warnings:

container/list/list.go:92:39: result 0 (*container/list.Element) is just parameter e
container/list/list.go:109:35: result 0 (*container/list.Element) is just parameter e
crypto/rsa/rsa.go:348:54: result 0 (*math/big.Int) is just parameter c
crypto/tls/conn.go:163:47: result 0 (error) is just parameter err
crypto/tls/conn.go:537:50: result 0 (*crypto/tls.block) is just parameter b
crypto/tls/tls.go:194:40: result 1 (error) is just parameter err
go/ast/commentmap.go:246:46: result 0 (go/ast.Node) is just parameter new
go/build/build.go:1125:61: result 1 (map[string][]go/token.Position) is just parameter m
go/parser/parser.go:227:35: result 0 (*go/parser.parser) is just parameter p
html/template/template.go:367:35: result 0 (*html/template.Template) is just parameter t
internal/testenv/testenv.go:228:33: result 0 (*os/exec.Cmd) is just parameter cmd
math/big/int.go:231:43: result 1 (*math/big.Int) is just parameter r
math/big/int.go:289:43: result 1 (*math/big.Int) is just parameter m
os/file.go:266:39: result 1 (error) is just parameter err
runtime/trace.go:635:67: result 1 (*runtime.traceBufPtr) is just parameter bufp
text/template/helper.go:21:35: result 0 (*text/template.Template) is just parameter t

None of them seem particularly good warnings. Thoughts? Perhaps run the tool on your codebases, grep for this new warning, and let me know if any of the warnings are actually useful.

mvdan added a commit that referenced this issue Nov 17, 2017
It was rarely useful, and it was particularly annoying with patterns
where funcs would return the same parameters they got, which would make
for simpler statements and expression when chaining these funcs or when
using them as return arguments.

See the discussion in #18.

Shaves off 19 warnings off std cmd, which were mostly false positives
like the above.
@mvdan
Copy link
Owner Author

mvdan commented Nov 17, 2017

I have found the pattern of false positives. It's usually like:

func transformFoo(f *Foo) *Foo {
    f.Field = "bar"
}

[...]

func SomeCode(f *Foo) {
    SomeOtherCode(transformFoo(f))
    // or: return transformFoo(f)
}

I've analysed this check in other codebases as well as std cmd and my own, and a vast majority of them aren't useful warnings. A few could be useful, and we could skip the check for the patterns above, but I struggle to see how it could be useful with even all of those.

Disabling the check for now. If anyone wants to give it a test-run, they can always revert 18c5021 (or go to the commit right before it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants