-
Notifications
You must be signed in to change notification settings - Fork 18k
x/tools/passes/printf: conditionally printf-like functions are treated as printf-like, causing false positives #73485
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
Comments
I tried reproducing it with the following code (without success): package main
import (
"fmt"
"testing"
)
func NewRule[T any]() Rule[T] {
return Rule[T]{}
}
type Rule[T any] struct {
details string
}
func (r Rule[T]) WithDetails(format string, a ...any) Rule[T] {
if len(a) == 0 {
r.details = format
} else {
r.details = fmt.Sprintf(format, a...)
}
return r
}
func TestRule_WithDetails(t *testing.T) {
tests := []struct {
Details string
OtherStuff string
}{
{
OtherStuff: "this",
Details: "details",
},
{
Details: "",
},
{
OtherStuff: "that",
Details: "details",
},
}
for _, test := range tests {
rule := NewRule[string]().
WithDetails(test.Details)
if rule.details == "foo" {
return
}
}
} |
What's happening here is that the presence of the func (r Rule[T]) WithDetails(format string, a ...any) Rule[T] {
if len(a) == 0 {
r.details = format
} else {
r.details = fmt.Sprintf(format, a...) // this call causes the analysis to inductively deduce that WithDetails is printf-like
}
return r
} Of course, your intent is that WithDetails is not actually printf-like, or at least not always: it is conditionally printf-like depending on the presence of arguments. However it is beyond the ability of the static checker to make that kind of deduction. As a matter of style, I would strongly suggest avoiding functions that are conditionally printf-like; it is as confusing to humans as it is to tools. (I routinely make this suggestion when reviewing Google's Go code.) Instead, rename it to WithDetailsf and remove the len(a)==0 part. Or, provide two variants, like the log package does. |
I assumed I'm missing something here, and indeed I was 🤦 And yes, I think I will follow your advice and adjust the API of the package accordingly. While I personally prefer the ease of use of the single printf-like function I'd much rather sacrifice that in order to be in line with the Go standards. Closing as resolved. |
Go version
go1.24.1
Output of
go env
in your module/workspace:What did you do?
I've bumped Go version in my project from 1.22 to 1.24 and
go vet
started failing.The internal implementation of
WithDetails
method looks like this:The failing test case looks like this:
What helped? Changing the test and adding the args:
While I can live with that fix, It seems to me like there's something potentially wrong with how
go vet
evaluates this rule. I tried reproducing that with a simpler code base, but couldn't reproduce it.PR link: nobl9/govy#104
Affected changes (before the fix): https://github.com/nobl9/govy/pull/104/files/1d63aadbad94f2aae90129e061f53c211e842361
What did you see happen?
What did you expect to see?
No errors reported by go vet as these test scenarios and the usage of reported methods
WithMessage
andWithDetails
are valid.The text was updated successfully, but these errors were encountered: