-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
x/tools/cmd/deadcode: unexported methods not reported as unreachable #65915
Comments
CC @adonovan |
From my digging, here's what I've found - in deadcode.go, we are utilizing ssautil's AllFunctions to get a list of functions from our program. in ssautil/visit.go we have the following code:
since the example struct is a type, and not a function, we call exportedTypeHack on it exportedTypeHack, in turn, will only get named parameters if they are exported -- see this causes any functions belonging to the unexported example struct to not be included in our list returned by AllFunctions. removing the call to i myself am not positive that this will not induce negative side-effects elsewhere, but I figured i'd throw this out as a lead to someone who is more familiarized with this codebase than me |
Change https://go.dev/cl/566421 mentions this issue: |
The fix seems reasonable, but...
I share this concern. This will need an investigation to make sure the cure is not worse than this issue. |
I will note that it is possible in some cases for methods on unexported structs to be correctly marked as deadcode. Running
I unfortunately haven't been able to replicate what causes this to happen with a more succinct example that is sharable, but did want to clarify that in some cases these methods can actually be identified. |
Surprisingly, the addition of a example/main.go
The output of
The output of
|
interestingly enough, when we call rta.Analyze in deadcode.go, we only check/set functions considered "Reachable" as true in the reachablePosn map, but it seems that when the fmt.Println() is added we start to consider almost everything reachable? consider the following example, utilizing this print statement in main.go (not the best debugging tool I am aware :P) example/main.go
as seen in deadcode.go
will produce the following result -
however, if we uncomment our println in main.go, it seems as though we print almost everything?
(etc, etc, etc) looking into why this happens now, but its quite interesting |
Change https://go.dev/cl/567156 mentions this issue: |
Many thanks for the bug report and especially the minimal test case. The problem is indeed in AllFunctions, but the fix is not in that function: it's not to use it at all. AllFunctions performs a reachability analysis, which is not appropriate for the "denominator" of a dead code analysis. (The "numerator" is of course RTA, a more precise reachability analysis.) The correct denominator is the set of all source-level named functions, which is (happily) much cheaper to compute. I mailed a fix in CL 567156. |
AllFunction's use of a reachability analysis is the explanation of this paradoxical behavior: the print statement causes the |
Thanks for the prompt investigation, explanation, and fix! |
Go version
go version go1.21.0 darwin/amd64
Output of
go env
in your module/workspace:What did you do?
go.mod
example/main.go
What did you see happen?
The output of
deadcode ./...
reports:In this case, the non-used methods on
example
(UnUsed
andunUsed
) should be reported as unreachable, but they weren't.The output of
deadcode -whylive scratchpad/example.example.UnUsed ./...
mistakenly reports:The output of
deadcode -whylive scratchpad/example.PublicExample.UnUsed ./...
correctly reports:What did you expect to see?
The output of
deadcode ./...
should report:The output of
deadcode -whylive scratchpad/example.example.UnUsed ./...
should report:The text was updated successfully, but these errors were encountered: