summaryrefslogtreecommitdiff
path: root/src/cmd/govet/govet.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/govet/govet.go')
-rw-r--r--src/cmd/govet/govet.go62
1 files changed, 44 insertions, 18 deletions
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
index b811c61a2..5b24d2ff0 100644
--- a/src/cmd/govet/govet.go
+++ b/src/cmd/govet/govet.go
@@ -15,6 +15,7 @@ import (
"go/token"
"os"
"path/filepath"
+ "reflect"
"strconv"
"strings"
"utf8"
@@ -50,7 +51,7 @@ func main() {
flag.Parse()
if *printfuncs != "" {
- for _, name := range strings.Split(*printfuncs, ",", -1) {
+ for _, name := range strings.Split(*printfuncs, ",") {
if len(name) == 0 {
flag.Usage()
}
@@ -59,7 +60,7 @@ func main() {
var err os.Error
skip, err = strconv.Atoi(name[colon+1:])
if err != nil {
- error(`illegal format for "Func:N" argument %q; %s`, name, err)
+ errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
}
name = name[:colon]
}
@@ -93,7 +94,7 @@ func doFile(name string, reader io.Reader) {
fs := token.NewFileSet()
parsedFile, err := parser.ParseFile(fs, name, reader, 0)
if err != nil {
- error("%s: %s", name, err)
+ errorf("%s: %s", name, err)
return
}
file := &File{fs.File(parsedFile.Pos())}
@@ -121,7 +122,7 @@ func walkDir(root string) {
done := make(chan bool)
go func() {
for e := range errors {
- error("walk error: %s", e)
+ errorf("walk error: %s", e)
}
done <- true
}()
@@ -132,7 +133,7 @@ func walkDir(root string) {
// error formats the error to standard error, adding program
// identification and a newline
-func error(format string, args ...interface{}) {
+func errorf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
setExit(2)
}
@@ -185,15 +186,35 @@ func (f *File) checkFile(name string, file *ast.File) {
// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
- // TODO: could return nil for nodes that cannot contain a CallExpr -
- // will shortcut traversal. Worthwhile?
switch n := node.(type) {
case *ast.CallExpr:
f.checkCallExpr(n)
+ case *ast.Field:
+ f.checkFieldTag(n)
}
return f
}
+// checkField checks a struct field tag.
+func (f *File) checkFieldTag(field *ast.Field) {
+ if field.Tag == nil {
+ return
+ }
+
+ tag, err := strconv.Unquote(field.Tag.Value)
+ if err != nil {
+ f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+ return
+ }
+
+ // Check tag for validity by appending
+ // new key:value to end and checking that
+ // the tag parsing code can find it.
+ if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
+ f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
+ return
+ }
+}
// checkCallExpr checks a call expression.
func (f *File) checkCallExpr(call *ast.CallExpr) {
@@ -358,19 +379,24 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
}
// This function never executes, but it serves as a simple test for the program.
-// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go
+// Test with make test.
func BadFunctionUsedInTests() {
- fmt.Println() // niladic call
- fmt.Println("%s", "hi") // % in call to Println
- fmt.Printf("%s", "hi", 3) // wrong # percents
- fmt.Printf("%s%%%d", "hi", 3) // right # percents
- fmt.Printf("%.*d", 3, 3) // right # percents, with a *
- fmt.Printf("%.*d", 3, 3, 3) // wrong # percents, with a *
- printf("now is the time", "buddy") // no %s
- Printf("now is the time", "buddy") // no %s
+ fmt.Println() // not an error
+ fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
+ fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args in Printf call"
+ fmt.Printf("%s%%%d", "hi", 3) // correct
+ fmt.Printf("%.*d", 3, 3) // correct
+ fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args in Printf call"
+ printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("hi") // ok
f := new(File)
- f.Warn(0, "%s", "hello", 3) // % in call to added function
- f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function
+ f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
+ f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
+}
+
+type BadTypeUsedInTests struct {
+ X int "hello" // ERROR "struct field tag"
}
// printf is used by the test.