Skip to content

Commit

Permalink
Merge pull request #38 from gostaticanalysis/add-field
Browse files Browse the repository at this point in the history
Add Field
  • Loading branch information
tenntenn authored Nov 19, 2020
2 parents 2f839a0 + 2d8f64e commit 91ab8b6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
24 changes: 24 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ func HasField(s *types.Struct, f *types.Var) bool {
return false
}

// Field returns field of the struct type.
// If the type is not struct or has not the field,
// Field returns -1, nil.
// If the type is a named type or a pointer type,
// Field calls itself recursively with
// an underlying type or an element type of pointer.
func Field(t types.Type, name string) (int, *types.Var) {
switch t := t.(type) {
case *types.Pointer:
return Field(t.Elem(), name)
case *types.Named:
return Field(t.Underlying(), name)
case *types.Struct:
for i := 0; i < t.NumFields(); i++ {
f := t.Field(i)
if f.Name() == name {
return i, f
}
}
}

return -1, nil
}

func TypesInfo(info ...*types.Info) *types.Info {
if len(info) == 0 {
return nil
Expand Down
55 changes: 55 additions & 0 deletions types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,58 @@ func TestUnder(t *testing.T) {
})
}
}

func TestField(t *testing.T) {
t.Parallel()

lookup := func(pass *analysis.Pass, n string) (types.Type, error) {
_, obj := pass.Pkg.Scope().LookupParent(n, token.NoPos)
if obj == nil {
return nil, fmt.Errorf("does not find: %s", n)
}
return obj.Type(), nil
}

cases := map[string]struct {
src string
typ string
field string
want int
}{
"nomarl": {"type a struct{n int}", "a", "n", 0},
"nofield": {"type a struct{n int}", "a", "m", -1},
"empty": {"type a struct{}", "a", "n", -1},
"two": {"type a struct{n, m int}", "a", "m", 1},
"nonamed": {"var a struct{n, m int}", "a", "m", 1},
"ptr": {"var a *struct{n, m int}", "a", "m", 1},
"namednamed": {"type a struct{n int}; type b a", "b", "n", 0},
"alias": {"type a struct{n int}; type b = a", "b", "n", 0},
}

for name, tt := range cases {
name, tt := name, tt
t.Run(name, func(t *testing.T) {
t.Parallel()
a := &analysis.Analyzer{
Name: name + "Analyzer",
Run: func(pass *analysis.Pass) (interface{}, error) {
typ, err := lookup(pass, tt.typ)
if err != nil {
return nil, err
}

got, _ := analysisutil.Field(typ, tt.field)
if tt.want != got {
return nil, fmt.Errorf("want %v but got %v", tt.want, got)
}
return nil, nil
},
}
path := filepath.Join(name, name+".go")
dir := WriteFiles(t, map[string]string{
path: fmt.Sprintf("package %s\n%s", name, tt.src),
})
analysistest.Run(t, dir, a, name)
})
}
}

0 comments on commit 91ab8b6

Please sign in to comment.