-
Notifications
You must be signed in to change notification settings - Fork 23
Refactor struct field selection to Inspector helper #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ type CommentStartTestStruct struct { | |
|
|
||
| StructForInlineField `json:",inline"` | ||
|
|
||
| A `json:"a"` // want "field A is missing godoc comment" | ||
|
|
||
| // IncorrectStartComment is a field with an incorrect start to the comment. // want "godoc for field IncorrectStartComment should start with 'incorrectStartComment ...'" | ||
| IncorrectStartComment string `json:"incorrectStartComment"` | ||
|
|
||
|
|
@@ -53,6 +55,10 @@ type StructForInlineField struct { | |
| NoComment string `json:"noComment"` // want "field NoComment is missing godoc comment" | ||
| } | ||
|
|
||
| type A struct { | ||
| NoComment string `json:"noComment"` // want "field NoComment is missing godoc comment" | ||
| } | ||
|
|
||
| type unexportedStruct struct { | ||
| NoComment string `json:"noComment"` // want "field NoComment is missing godoc comment" | ||
| } | ||
|
|
@@ -71,3 +77,7 @@ func FunctionWithStructs() { | |
| NoComment string `json:"noComment"` | ||
| } | ||
| } | ||
|
|
||
| type Interface interface { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we also need to test a type that uses composition of the interface like: type ComposedThing struct {
Interface
Foo string
}? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Apparently you can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would just mean you have to initialise the interface, inside the struct, with something that implements the interface. At the moment I can't see why anyone would be using that inside a Kube API type, but maybe there are other types in the same package that this might effect? For now I'm tempted to leave this out until we see a use case |
||
| InaccessibleFunction() string | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package inspector | ||
|
|
||
| import ( | ||
| "errors" | ||
| "reflect" | ||
|
|
||
| "golang.org/x/tools/go/analysis" | ||
| "golang.org/x/tools/go/analysis/passes/inspect" | ||
| astinspector "golang.org/x/tools/go/ast/inspector" | ||
|
|
||
| "github.com/JoelSpeed/kal/pkg/analysis/helpers/extractjsontags" | ||
| "github.com/JoelSpeed/kal/pkg/analysis/helpers/markers" | ||
| ) | ||
|
|
||
| const name = "inspector" | ||
|
|
||
| var ( | ||
| errCouldNotGetInspector = errors.New("could not get inspector") | ||
| errCouldNotGetJSONTags = errors.New("could not get json tags") | ||
| errCouldNotGetMarkers = errors.New("could not get markers") | ||
| ) | ||
|
|
||
| // Analyzer is the analyzer for the inspector package. | ||
| // It provides common functionality for analyzers that need to inspect fields and struct. | ||
| // Abstracting away filtering of fields that the analyzers should and shouldn't be worrying about. | ||
| var Analyzer = &analysis.Analyzer{ | ||
| Name: name, | ||
| Doc: "Provides common functionality for analyzers that need to inspect fields and struct", | ||
| Run: run, | ||
| Requires: []*analysis.Analyzer{inspect.Analyzer, extractjsontags.Analyzer, markers.Analyzer}, | ||
| ResultType: reflect.TypeOf(newInspector(nil, nil, nil)), | ||
| } | ||
|
|
||
| func run(pass *analysis.Pass) (interface{}, error) { | ||
| astinspector, ok := pass.ResultOf[inspect.Analyzer].(*astinspector.Inspector) | ||
| if !ok { | ||
| return nil, errCouldNotGetInspector | ||
| } | ||
|
|
||
| jsonTags, ok := pass.ResultOf[extractjsontags.Analyzer].(extractjsontags.StructFieldTags) | ||
| if !ok { | ||
| return nil, errCouldNotGetJSONTags | ||
| } | ||
|
|
||
| markersAccess, ok := pass.ResultOf[markers.Analyzer].(markers.Markers) | ||
| if !ok { | ||
| return nil, errCouldNotGetMarkers | ||
| } | ||
|
|
||
| return newInspector(astinspector, jsonTags, markersAccess), nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package inspector_test | ||
|
|
||
| import ( | ||
| "errors" | ||
| "go/ast" | ||
| "testing" | ||
|
|
||
| "github.com/JoelSpeed/kal/pkg/analysis/helpers/extractjsontags" | ||
| "github.com/JoelSpeed/kal/pkg/analysis/helpers/inspector" | ||
| "github.com/JoelSpeed/kal/pkg/analysis/helpers/markers" | ||
| "golang.org/x/tools/go/analysis" | ||
| "golang.org/x/tools/go/analysis/analysistest" | ||
| ) | ||
|
|
||
| func TestInspector(t *testing.T) { | ||
| testdata := analysistest.TestData() | ||
|
|
||
| analysistest.Run(t, testdata, testAnalyzer, "a") | ||
| } | ||
|
|
||
| var errCouldNotGetInspector = errors.New("could not get inspector") | ||
|
|
||
| var testAnalyzer = &analysis.Analyzer{ | ||
| Name: "test", | ||
| Doc: "tests the inspector analyzer", | ||
| Run: run, | ||
| Requires: []*analysis.Analyzer{inspector.Analyzer}, | ||
| } | ||
|
|
||
| func run(pass *analysis.Pass) (interface{}, error) { | ||
| inspect, ok := pass.ResultOf[inspector.Analyzer].(inspector.Inspector) | ||
| if !ok { | ||
| return nil, errCouldNotGetInspector | ||
| } | ||
|
|
||
| inspect.InspectFields(func(field *ast.Field, stack []ast.Node, jsonTagInfo extractjsontags.FieldTagInfo, markersAccess markers.Markers) { | ||
| var fieldName string | ||
| if len(field.Names) > 0 { | ||
| fieldName = field.Names[0].Name | ||
| } else if ident, ok := field.Type.(*ast.Ident); ok { | ||
| fieldName = ident.Name | ||
| } | ||
|
|
||
| pass.Reportf(field.Pos(), "field: %v", fieldName) | ||
|
|
||
| if jsonTagInfo.Name != "" { | ||
| pass.Reportf(field.Pos(), "json tag: %v", jsonTagInfo.Name) | ||
| } | ||
| }) | ||
|
|
||
| return nil, nil //nolint:nilnil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /* | ||
| inspector is a helper package that iterates over fields in structs, calling an inspection function on fields | ||
| that should be considered for analysis. | ||
|
|
||
| The inspector extracts common logic of iterating and filtering through struct fields, so that analyzers | ||
| need not re-implement the same filtering over and over. | ||
|
|
||
| For example, the inspector filters out struct definitions that are not type declarations, and fields that are ignored. | ||
|
|
||
| Example: | ||
|
|
||
| type A struct { | ||
| // This field is included in the analysis. | ||
| Field string `json:"field"` | ||
|
|
||
| // This field, and the fields within are ignored due to the json tag. | ||
| F struct { | ||
| Field string `json:"field"` | ||
| } `json:"-"` | ||
| } | ||
|
|
||
| // Any struct defined within a function is ignored. | ||
| func Foo() { | ||
| type Bar struct { | ||
| Field string | ||
| } | ||
| } | ||
|
|
||
| // All fields within interface declarations are ignored. | ||
| type Bar interface { | ||
| Name() string | ||
| } | ||
| */ | ||
| package inspector |
Uh oh!
There was an error while loading. Please reload this page.