@@ -19,8 +19,8 @@ import (
19
19
"fmt"
20
20
"go/ast"
21
21
"strconv"
22
- "strings"
23
22
23
+ "golang.org/x/tools/go/packages"
24
24
"sigs.k8s.io/controller-tools/pkg/crd"
25
25
"sigs.k8s.io/controller-tools/pkg/loader"
26
26
"sigs.k8s.io/controller-tools/pkg/markers"
@@ -79,20 +79,21 @@ func (im importIdents) findPackagePathForSelExpr(expr *ast.SelectorExpr) (pkgPat
79
79
80
80
// Short-circuit if only one import.
81
81
if len (imports ) == 1 {
82
- return imports [0 ].path
83
- }
84
-
85
- // If multiple files contain the same local import name, check to see which file contains the selector expression.
86
- for _ , imp := range imports {
87
- if imp .f .Pos () <= expr .Pos () && imp .f .End () >= expr .End () {
88
- return imp .path
82
+ pkgPath = imports [0 ].path
83
+ } else {
84
+ // If multiple files contain the same local import name, check to see which file contains the selector expression.
85
+ for _ , imp := range imports {
86
+ if imp .f .Pos () <= expr .Pos () && imp .f .End () >= expr .End () {
87
+ pkgPath = imp .path
88
+ break
89
+ }
89
90
}
90
91
}
91
- return ""
92
+ return loader . NonVendorPath ( pkgPath )
92
93
}
93
94
94
95
// getMarkedChildrenOfField collects all marked fields from type declarations starting at rootField in depth-first order.
95
- func (g generator ) getMarkedChildrenOfField (rootPkg * loader.Package , rootField markers.FieldInfo ) (map [string ][]* fieldInfo , error ) {
96
+ func (g generator ) getMarkedChildrenOfField (rootPkg * loader.Package , rootField markers.FieldInfo ) (map [crd. TypeIdent ][]* fieldInfo , error ) {
96
97
// Gather all types and imports needed to build the BFS tree.
97
98
rootPkg .NeedTypesInfo ()
98
99
importIDs , err := newImportIdents (rootPkg )
@@ -102,50 +103,46 @@ func (g generator) getMarkedChildrenOfField(rootPkg *loader.Package, rootField m
102
103
103
104
// ast.Inspect will not traverse into fields, so iteratively collect them and to check for markers.
104
105
nextFields := []* fieldInfo {{FieldInfo : rootField }}
105
- markedFields := map [string ][]* fieldInfo {}
106
+ markedFields := map [crd. TypeIdent ][]* fieldInfo {}
106
107
for len (nextFields ) > 0 {
107
108
fields := []* fieldInfo {}
108
109
for _ , field := range nextFields {
109
- errs := []error {}
110
110
ast .Inspect (field .RawField , func (n ast.Node ) bool {
111
111
if n == nil {
112
112
return true
113
113
}
114
114
115
- var info * markers.TypeInfo
116
- var hasInfo bool
115
+ var ident crd.TypeIdent
117
116
switch nt := n .(type ) {
118
- case * ast.SelectorExpr :
119
- // Case of a type definition in an imported package.
120
-
117
+ case * ast.SelectorExpr : // Type definition in an imported package.
121
118
pkgPath := importIDs .findPackagePathForSelExpr (nt )
122
119
if pkgPath == "" {
123
120
// Found no reference to pkgPath in any file.
124
121
return true
125
122
}
126
- if pkg , hasImport := rootPkg .Imports ()[loader . NonVendorPath ( pkgPath ) ]; hasImport {
127
- // Check if the field's type exists in the known types.
128
- info , hasInfo = g . types [ crd.TypeIdent {Package : pkg , Name : nt .Sel .Name }]
123
+ if pkg , hasImport := rootPkg .Imports ()[pkgPath ]; hasImport {
124
+ pkg . NeedTypesInfo ()
125
+ ident = crd.TypeIdent {Package : pkg , Name : nt .Sel .Name }
129
126
}
130
- case * ast.Ident :
131
- // Case of a local type definition.
132
-
133
- // Only look at type names.
134
- if nt .Obj != nil && nt .Obj .Kind == ast .Typ {
135
- // Check if the field's type exists in the known types.
136
- info , hasInfo = g .types [crd.TypeIdent {Package : rootPkg , Name : nt .Name }]
127
+ case * ast.Ident : // Local type definition.
128
+ // Only look at type idents or references to type idents in other files.
129
+ if nt .Obj == nil || nt .Obj .Kind == ast .Typ {
130
+ ident = crd.TypeIdent {Package : rootPkg , Name : nt .Name }
137
131
}
138
132
}
139
- if ! hasInfo {
133
+
134
+ // Check if the field's type is a known types.
135
+ info , hasInfo := g .types [ident ]
136
+ if ident == (crd.TypeIdent {}) || ! hasInfo {
140
137
return true
141
138
}
142
139
143
140
// Add all child fields to the list to search next.
144
141
for _ , finfo := range info .Fields {
145
142
segment , err := getPathSegmentForField (finfo )
146
143
if err != nil {
147
- errs = append ( errs , fmt .Errorf ("error getting path from type %s field %s: %v" , info .Name , finfo .Name , err ))
148
- return true
144
+ rootPkg . AddError ( fmt .Errorf ("error getting path from type %s field %s: %v" , info .Name , finfo .Name , err ))
145
+ continue
149
146
}
150
147
// Add extra information to the segment if it comes from a certain field type.
151
148
switch finfo .RawField .Type .(type ) {
@@ -166,33 +163,19 @@ func (g generator) getMarkedChildrenOfField(rootPkg *loader.Package, rootField m
166
163
fields = append (fields , f )
167
164
// Marked fields get collected for the caller to parse.
168
165
if len (finfo .Markers ) != 0 {
169
- markedFields [info . Name ] = append (markedFields [info . Name ], f )
166
+ markedFields [ident ] = append (markedFields [ident ], f )
170
167
}
171
168
}
172
169
173
170
return true
174
171
})
175
- if err := fmtParseErrors (errs ); err != nil {
176
- return nil , err
177
- }
178
172
}
179
173
nextFields = fields
180
174
}
181
- return markedFields , nil
182
- }
183
175
184
- // fmtParseErrors prettifies a list of errors to make them easier to read.
185
- func fmtParseErrors (errs []error ) error {
186
- switch len (errs ) {
187
- case 0 :
188
- return nil
189
- case 1 :
190
- return errs [0 ]
176
+ if loader .PrintErrors ([]* loader.Package {rootPkg }, packages .TypeError ) {
177
+ return nil , errors .New ("package had type errors" )
191
178
}
192
- sb := strings.Builder {}
193
- for _ , err := range errs {
194
- sb .WriteString ("\n " )
195
- sb .WriteString (err .Error ())
196
- }
197
- return errors .New (sb .String ())
179
+
180
+ return markedFields , nil
198
181
}
0 commit comments