diff --git a/pkg/analyzer/analyzer.go b/pkg/analyzer/analyzer.go index 49948e12..4da98842 100644 --- a/pkg/analyzer/analyzer.go +++ b/pkg/analyzer/analyzer.go @@ -21,10 +21,10 @@ type analyzer struct { include PatternsList exclude PatternsList - typesProcessCache map[string]bool + typesProcessCache map[types.Type]bool typesProcessCacheMu sync.RWMutex - structFieldsCache map[string]*StructFields + structFieldsCache map[types.Type]*StructFields structFieldsCacheMu sync.RWMutex } @@ -33,9 +33,9 @@ type analyzer struct { // -e arguments adds exclude patterns func NewAnalyzer(include []string, exclude []string) (*analysis.Analyzer, error) { a := analyzer{ //nolint:exhaustruct - typesProcessCache: map[string]bool{}, + typesProcessCache: map[types.Type]bool{}, - structFieldsCache: map[string]*StructFields{}, + structFieldsCache: map[types.Type]*StructFields{}, } var err error @@ -123,7 +123,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { return } - if !a.shouldProcessType(typ.String()) { + if !a.shouldProcessType(typ) { return } @@ -138,7 +138,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { } } - missingFields := a.structMissingFields(lit, strct, typ.String(), pass.Pkg.Path()) + missingFields := a.structMissingFields(lit, strct, strings.HasPrefix(typ.String(), pass.Pkg.Path()+".")) if len(missingFields) == 1 { pass.Reportf(node.Pos(), "%s is missing in %s", missingFields[0], strctName) @@ -148,7 +148,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { } } -func (a *analyzer) shouldProcessType(typ string) bool { +func (a *analyzer) shouldProcessType(typ types.Type) bool { if len(a.include) == 0 && len(a.exclude) == 0 { // skip whole part with cache, since we have no restrictions and have to check everything return true @@ -163,12 +163,13 @@ func (a *analyzer) shouldProcessType(typ string) bool { defer a.typesProcessCacheMu.Unlock() v = true + typStr := typ.String() - if len(a.include) > 0 && !a.include.MatchesAny(typ) { + if len(a.include) > 0 && !a.include.MatchesAny(typStr) { v = false } - if v && a.exclude.MatchesAny(typ) { + if v && a.exclude.MatchesAny(typStr) { v = false } @@ -178,18 +179,13 @@ func (a *analyzer) shouldProcessType(typ string) bool { return v } -func (a *analyzer) structMissingFields( - lit *ast.CompositeLit, - strct *types.Struct, - typ string, - pkgPath string, -) []string { +func (a *analyzer) structMissingFields(lit *ast.CompositeLit, strct *types.Struct, private bool) []string { keys, unnamed := literalKeys(lit) - fields := a.structFields(typ, strct) + fields := a.structFields(strct) var fieldNames []string - if strings.HasPrefix(typ, pkgPath+".") { + if private { // we're in same package and should match private fields fieldNames = fields.All } else { @@ -203,7 +199,9 @@ func (a *analyzer) structMissingFields( return difference(fieldNames, keys) } -func (a *analyzer) structFields(typ string, strct *types.Struct) *StructFields { +func (a *analyzer) structFields(strct *types.Struct) *StructFields { + typ := strct.Underlying() + a.structFieldsCacheMu.RLock() fields, ok := a.structFieldsCache[typ] a.structFieldsCacheMu.RUnlock() diff --git a/pkg/analyzer/struct-fields.go b/pkg/analyzer/struct-fields.go index e7d00425..59b755f0 100644 --- a/pkg/analyzer/struct-fields.go +++ b/pkg/analyzer/struct-fields.go @@ -5,18 +5,20 @@ import ( ) type StructFields struct { + All []string Public []string - - All []string } func NewStructFields(strct *types.Struct) *StructFields { - sf := StructFields{} //nolint:exhaustruct + sf := StructFields{ + All: make([]string, strct.NumFields()), + Public: []string{}, + } for i := 0; i < strct.NumFields(); i++ { f := strct.Field(i) - sf.All = append(sf.All, f.Name()) + sf.All[i] = f.Name() if f.Exported() { sf.Public = append(sf.Public, f.Name()) diff --git a/testdata/src/s/s.go b/testdata/src/s/s.go index a199f565..615bebd3 100644 --- a/testdata/src/s/s.go +++ b/testdata/src/s/s.go @@ -34,6 +34,25 @@ func shouldPass() Test { } } +func shouldPassPrivateLocalTypeCorrect1() { + type myTpe struct { + a string + b string + } + + _ = myTpe{"", ""} +} + +func shouldPassPrivateLocalTypeCorrect2() { + type myTpe struct { + a string + b string + c string + } + + _ = myTpe{"", "", ""} +} + func shouldPass2() Test2 { return Test2{ External: e.External{