Skip to content

Commit 348b35b

Browse files
committed
feat: add ability to mark field as optional with help of field tag
1 parent ed5a197 commit 348b35b

File tree

5 files changed

+52
-15
lines changed

5 files changed

+52
-15
lines changed

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module github.com/GaijinEntertainment/go-exhaustruct/v2
22

33
go 1.18
44

5-
require golang.org/x/tools v0.1.12
5+
require (
6+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
7+
golang.org/x/tools v0.1.12
8+
)
69

710
require (
811
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
2+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
13
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
24
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
35
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=

pkg/analyzer/analyzer.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,19 @@ func (a *analyzer) structMissingFields(lit *ast.CompositeLit, strct *types.Struc
183183
keys, unnamed := literalKeys(lit)
184184
fields := a.structFields(strct)
185185

186-
var fieldNames []string
186+
if unnamed {
187+
if private {
188+
return fields.All[len(keys):]
189+
}
187190

188-
if private {
189-
// we're in same package and should match private fields
190-
fieldNames = fields.All
191-
} else {
192-
fieldNames = fields.Public
191+
return fields.Public[len(keys):]
193192
}
194193

195-
if unnamed {
196-
return fieldNames[len(keys):]
194+
if private {
195+
return difference(fields.AllRequired, keys)
197196
}
198197

199-
return difference(fieldNames, keys)
198+
return difference(fields.PublicRequired, keys)
200199
}
201200

202201
func (a *analyzer) structFields(strct *types.Struct) *StructFields {

pkg/analyzer/struct-fields.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,60 @@ package analyzer
22

33
import (
44
"go/types"
5+
"reflect"
6+
7+
"golang.org/x/exp/slices"
58
)
69

710
type StructFields struct {
8-
All []string
9-
Public []string
11+
All []string
12+
AllRequired []string
13+
14+
Public []string
15+
PublicRequired []string
1016
}
1117

1218
func NewStructFields(strct *types.Struct) *StructFields {
1319
sf := StructFields{
14-
All: make([]string, strct.NumFields()),
15-
Public: []string{},
20+
All: make([]string, strct.NumFields()),
21+
AllRequired: make([]string, 0, strct.NumFields()),
22+
Public: make([]string, 0, strct.NumFields()),
23+
PublicRequired: make([]string, 0, strct.NumFields()),
1624
}
1725

1826
for i := 0; i < strct.NumFields(); i++ {
1927
f := strct.Field(i)
28+
isOptional := isFieldOptional(strct.Tag(i))
2029

2130
sf.All[i] = f.Name()
31+
if !isOptional {
32+
sf.AllRequired = append(sf.AllRequired, f.Name())
33+
}
2234

2335
if f.Exported() {
2436
sf.Public = append(sf.Public, f.Name())
37+
38+
if !isOptional {
39+
sf.PublicRequired = append(sf.PublicRequired, f.Name())
40+
}
2541
}
2642
}
2743

44+
sf.All = slices.Clip(sf.All)
45+
sf.AllRequired = slices.Clip(sf.AllRequired)
46+
sf.Public = slices.Clip(sf.Public)
47+
sf.PublicRequired = slices.Clip(sf.PublicRequired)
48+
2849
return &sf
2950
}
51+
52+
const (
53+
TagName = "exhaustruct"
54+
OptionalTagValue = "optional"
55+
)
56+
57+
// isFieldOptional checks if field tags has an optional tag, and therefore can
58+
// be omitted during structure initialization.
59+
func isFieldOptional(tags string) bool {
60+
return reflect.StructTag(tags).Get(TagName) == OptionalTagValue
61+
}

testdata/src/s/s.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Test struct {
1818
B int
1919
C float32
2020
D bool
21+
E string `exhaustruct:"optional"`
2122
}
2223

2324
type Test2 struct {
@@ -84,7 +85,7 @@ func shouldPass3() {
8485
}
8586

8687
func shouldPassWithoutNames() Test {
87-
return Test{"", 0, 0, false}
88+
return Test{"", 0, 0, false, ""}
8889
}
8990

9091
func shouldFailWithReturn() (Test, error) {

0 commit comments

Comments
 (0)