Skip to content

Commit

Permalink
cmd/vet: ignore the content of tag values
Browse files Browse the repository at this point in the history
  • Loading branch information
zimmski committed Jan 17, 2015
1 parent 3ecc311 commit 4b82084
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 19 deletions.
82 changes: 65 additions & 17 deletions cmd/vet/structtag.go
Expand Up @@ -11,8 +11,8 @@ import (
"go/ast"
"reflect"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)

func init() {
Expand Down Expand Up @@ -70,33 +70,81 @@ var (
// in the canonical format, which is a space-separated list of key:"value"
// settings.
func validateStructTag(tag string) error {
elems := strings.Split(tag, " ")
for _, elem := range elems {
if elem == "" {
continue
}
fields := strings.SplitN(elem, ":", 2)
if len(fields) != 2 {
return errTagSyntax
l := len(tag)

for i := 0; i < l; i++ {
// Ignore spaces
for i < l && tag[i] == ' ' {
i++
}
key, value := fields[0], fields[1]
if len(key) == 0 || len(value) < 2 {
return errTagSyntax

if i >= l {
break
}

// Key must not contain control characters or quotes.
for _, r := range key {
if r == '"' || unicode.IsControl(r) {
j := i
for ; i < l; i++ {
if tag[i] == ':' {
// Key must not be empty
if i == j {
return errTagSyntax
}

i++

break
} else if r, w := utf8.DecodeRuneInString(tag[i:]); tag[i] == '"' || unicode.IsControl(r) {
return errTagKeySyntax
} else {
// Move i further along if we encountered an UTF8 character
if w > 1 {
i += w - 1
}
}
}
if value[0] != '"' || value[len(value)-1] != '"' {

// There must be room for a quoted string
if i > l-2 {
return errTagSyntax
}

// Check the starting quote
if tag[i] != '"' {
return errTagValueSyntax
}
// Value must be quoted string
_, err := strconv.Unquote(value)

j = i

// Jump over quote
i++

for i < l && tag[i] != '"' {
if tag[i] == '\\' {
i++
}

i++
}

// Check if there was an ending quote
if i >= l {
return errTagValueSyntax
}

// Jump over quote
i++

_, err := strconv.Unquote(tag[j:i])
if err != nil {
return errTagValueSyntax
}

// There must be at least one space between two pairs
if i < l && tag[i] != ' ' {
return errTagSyntax
}
}

return nil
}
8 changes: 6 additions & 2 deletions cmd/vet/testdata/structtag.go
Expand Up @@ -11,8 +11,12 @@ type StructTagTest struct {
B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
OK0 int `x:"y" u:"v" w:""`
OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
OK0 int `x:"y"`
OK1 int `x:"y" u:"v" w:""`
OK2 int `x:"y:z" u:"v" w:""` // note multiple colons.
OK3 int ` x:"y" u:"v" w:"" ` // ignore spaces outside of values
OK3 int `x:"y z"` // especially ignore spaces inside of values
OK4 int `x:"y\nz"` // ignore escaping
}

type UnexportedEncodingTagTest struct {
Expand Down

0 comments on commit 4b82084

Please sign in to comment.