Skip to content

Only assume named returns can be read via a panic if there was a defer.#61

Open
kyegupov wants to merge 1 commit intogordonklaus:masterfrom
kyegupov:fix/named-returns-only-read-when-has-defer
Open

Only assume named returns can be read via a panic if there was a defer.#61
kyegupov wants to merge 1 commit intogordonklaus:masterfrom
kyegupov:fix/named-returns-only-read-when-has-defer

Conversation

@kyegupov
Copy link
Copy Markdown

@kyegupov kyegupov commented Jun 4, 2021

This tightens the analysis which has become too lenient after fixing #22.
A possibility of panic can only lead to named returns being read if there is a "defer" statement which could call recover().

This tightens the analysis which has become too lenient after fixing gordonklaus#22.
A possibility of panic can only lead to named returns being read if there is a "defer" statement which could call recover().
Copy link
Copy Markdown
Owner

@gordonklaus gordonklaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I left some comments that need to be addressed before I can merge.

@@ -1,5 +1,7 @@
package ineffassign

// adapted from https://github.com/gordonklaus/ineffassign/blob/2e10b26642541670df2672e035b2de19fcb04cab/pkg/ineffassign/ineffassign.go
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete

roots []*block
block *block
vars map[*ast.Object]*variable
returnsStack []funcReturnSpec
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just call it returns

Comment on lines +168 to +169
for _, c0 := range n.Body.List {
c := c0.(*ast.CommClause).Comm
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

v.fundept++
}
bld.results = append(bld.results, typ.Results)
bld.returnsStack = append(bld.returnsStack, funcReturnSpec{results: typ.Results, hasDefer: false})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

omit hasDefer (zero value is false)

Comment on lines +325 to +329
lastIdx := len(bld.returnsStack) - 1
bld.returnsStack[lastIdx] = funcReturnSpec{
results: bld.returnsStack[lastIdx].results,
hasDefer: true,
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewrite these lines as just bld.returns[len(bld.returns)-1].hasDefer = true

case *ast.TypeAssertExpr:
bld.maybePanic()
return bld
case *ast.DeferStmt:
Copy link
Copy Markdown
Owner

@gordonklaus gordonklaus Jun 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A DeferStmt should have a little more special treatment. It has a CallExpr, but our handling of CallExpr (above) calls bld.maybePanic. But a defer statement doesn't actually call the function and cannot thusly panic, so this treatment is incorrect. We should call:

bld.walk(n.Call.Fun)
for _, x := range n.Call.Args {
    bld.walk(x)
}

before setting hasDefer = true and then do not call return bld after.

Please also add a couple of tests to ensure that named results are not marked as used just because there are defer statements. One test with one defer statement and one with two defers (and no maybe-panicking statements) should suffice.

This isn't a regression so it's not strictly necessary, in case you want to skip it. But since you're tightening the analysis I thought you might want to include this.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please move this case block up after case *ast.BranchStmt: to follow my rough code organization ;)


// An operation that might panic marks named function results as used.
// An operation that might panic marks named function results as used, if the function has a "defer" statement
// (and thus can potentially recover); see https://github.com/gordonklaus/ineffassign/issues/22
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to mention this issue since we're going to resolve it :)

Comment on lines +331 to +333
defer func() {
recover()
}()
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just write defer recover() if you're into the whole brevity thing

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants