cmd/vet: diagnose using Printf on a function value
Printing a function value is nearly useless outside of debugging, but
can occur by mistake when one forgets to call it. Diagnose this.
I did this myself just the other day and it arose in cl/14031.
Easy to fix and seems worthwhile.
Fixes #12295.
Change-Id: Ice125a84559f0394f7fa7272b5d31ae602b07f83
Reviewed-on: https://go-review.googlesource.com/14122
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index d79b096..5436c5b 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -447,6 +447,10 @@
arg := call.Args[argNum]
if !f.matchArgType(v.typ, nil, arg) {
typeString := ""
+ if f.isFunctionValue(arg) {
+ f.Badf(call.Pos(), "arg %s in printf call is a function value, not a function call", f.gofmt(arg))
+ return false
+ }
if typ := f.pkg.types[arg].Type; typ != nil {
typeString = typ.String()
}
@@ -490,6 +494,16 @@
return f.stringers[obj]
}
+// isFunctionValue reports whether the expression is a function as opposed to a function call.
+// It is almost always a mistake to print a function value.
+func (f *File) isFunctionValue(e ast.Expr) bool {
+ if typ := f.pkg.types[e].Type; typ != nil {
+ _, ok := typ.(*types.Signature)
+ return ok
+ }
+ return false
+}
+
// argCanBeChecked reports whether the specified argument is statically present;
// it may be beyond the list of arguments or in a terminal slice... argument, which
// means we can't see it.
@@ -579,8 +593,11 @@
}
}
for _, arg := range args {
+ if f.isFunctionValue(arg) {
+ f.Badf(call.Pos(), "arg %s in %s call is a function value, not a function call", f.gofmt(arg), name)
+ }
if f.recursiveStringer(arg) {
- f.Badf(call.Pos(), "arg %s for print causes recursive call to String method", f.gofmt(arg))
+ f.Badf(call.Pos(), "arg %s in %s call causes recursive call to String method", f.gofmt(arg), name)
}
}
}