Skip to content

Commit

Permalink
Merge pull request #7 from tttoad/fix-parse-panic
Browse files Browse the repository at this point in the history
Fix: panic during tags processing
  • Loading branch information
4meepo committed Oct 19, 2023
2 parents 9e1a95f + cc14d3c commit 22ba94a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
38 changes: 32 additions & 6 deletions tagalign.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const (
StrictStyle
)

const (
errTagValueSyntax = "bad syntax for struct tag value"
)

func NewAnalyzer(options ...Option) *analysis.Analyzer {
return &analysis.Analyzer{
Name: "tagalign",
Expand Down Expand Up @@ -208,16 +212,25 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
uniqueKeys = append(uniqueKeys, k)
}

for i, field := range fields {
offsets[i] = pass.Fset.Position(field.Tag.Pos()).Column
for i := 0; i < len(fields); {
field := fields[i]
column := pass.Fset.Position(field.Tag.Pos()).Column - 1
offsets[i] = column

tag, err := strconv.Unquote(field.Tag.Value)
if err != nil {
break
// if tag value is not a valid string, report it directly
w.report(pass, field, column, errTagValueSyntax, field.Tag.Value)
fields = removeField(fields, i)
continue
}

tags, err := structtag.Parse(tag)
if err != nil {
break
// if tag value is not a valid struct tag, report it directly
w.report(pass, field, column, err.Error(), field.Tag.Value)
fields = removeField(fields, i)
continue
}

maxTagNum = max(maxTagNum, tags.Len())
Expand All @@ -234,6 +247,8 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
addKey(t.Key)
}
tagsGroup = append(tagsGroup, tags.Tags())

i++
}

if w.sort && StrictStyle == w.style {
Expand Down Expand Up @@ -325,19 +340,22 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit

msg := "tag is not aligned, should be: " + unquoteTag

w.report(pass, field, offsets[i]-1, msg, newTagValue)
w.report(pass, field, offsets[i], msg, newTagValue)
}
}

// process single fields
for _, field := range w.singleFields {
column := pass.Fset.Position(field.Tag.Pos()).Column - 1
tag, err := strconv.Unquote(field.Tag.Value)
if err != nil {
w.report(pass, field, column, errTagValueSyntax, field.Tag.Value)
continue
}

tags, err := structtag.Parse(tag)
if err != nil {
w.report(pass, field, column, err.Error(), field.Tag.Value)
continue
}
originalTags := append([]*structtag.Tag(nil), tags.Tags()...)
Expand All @@ -353,7 +371,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit

msg := "tag is not aligned , should be: " + tags.String()

w.report(pass, field, pass.Fset.Position(field.Tag.Pos()).Column-1, msg, newTagValue)
w.report(pass, field, column, msg, newTagValue)
}
}

Expand Down Expand Up @@ -431,3 +449,11 @@ func max(a, b int) int {
}
return b
}

func removeField(fields []*ast.Field, index int) []*ast.Field {
if index < 0 || index >= len(fields) {
return fields
}

return append(fields[:index], fields[index+1:]...)
}
9 changes: 9 additions & 0 deletions tagalign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func Test_alignAndSortWithOrder(t *testing.T) {
assert.NoError(t, err)
analysistest.Run(t, sort, a)
}

func TestSprintf(t *testing.T) {
format := alignFormat(20)
assert.Equal(t, "%-20s", format)
Expand Down Expand Up @@ -72,3 +73,11 @@ func Test_alignSingleField(t *testing.T) {
assert.NoError(t, err)
analysistest.Run(t, unsort, a)
}

func Test_badSyntaxTag(t *testing.T) {
// only align
a := NewAnalyzer()
unsort, err := filepath.Abs("testdata/bad_syntax_tag")
assert.NoError(t, err)
analysistest.Run(t, unsort, a)
}
17 changes: 17 additions & 0 deletions testdata/bad_syntax_tag/example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package issues6

type FooBar struct {
Foo int `json: "foo" validate:"required"` // want `bad syntax for struct tag value`
Bar string `json:bar` // want `bad syntax for struct tag value`
FooFoo int8 `json:"foo_foo" validate:"required"`
BarBar int `json:"bar_bar" validate:"required"`
}

type FooBar2 struct {
Foo int `json:"foo" validate:"required"`

FooFoo int8 `json:"foo_foo"`
BarBar int `json:"bar_bar" validate:"required"`
XXX int `json:"xxx" validate:"required"`
Bar string `json:bar` // want `bad syntax for struct tag value`
}

0 comments on commit 22ba94a

Please sign in to comment.