Skip to content

Commit

Permalink
Merge pull request #13 from Joffref/parse-method
Browse files Browse the repository at this point in the history
feat: parse methods
  • Loading branch information
Joffref authored Nov 10, 2023
2 parents d27dda7 + 80759af commit 8b3796a
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 10 deletions.
83 changes: 78 additions & 5 deletions internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,39 @@ import (
)

func Parse(pkg *packages.Package, structName string) (Struct, error) {
parsedStruct := Struct{Type: Type(structName)}
found := false
for ident := range pkg.TypesInfo.Defs {
if ident.Name == structName {
structType, err := identAsStructType(ident)
if err != nil {
return Struct{}, err
}

return Struct{
Type: Type(structName),
Attributes: structAttributes(pkg.TypesInfo, structType),
}, nil
parsedStruct.Attributes = structAttributes(pkg.TypesInfo, structType)
found = true
break
}
}
return Struct{}, fmt.Errorf("struct %s not found in package %s", structName, pkg.Name)
if !found {
return Struct{}, fmt.Errorf("struct %s not found in package %s", structName, pkg.Name)
}

for ident, object := range pkg.TypesInfo.Uses {
if ident.Name == structName {
namedType, err := objectAsNamedType(object)
if err != nil {
return Struct{}, err
}

parsedStruct.Methods, err = structMethods(namedType)
if err != nil {
return Struct{}, err
}
}
}

return parsedStruct, nil
}

func identAsStructType(ident *ast.Ident) (*ast.StructType, error) {
Expand All @@ -39,6 +58,19 @@ func identAsStructType(ident *ast.Ident) (*ast.StructType, error) {
return structDeclaration, nil
}

func objectAsNamedType(object types.Object) (*types.Named, error) {
typeName, isTypeName := object.(*types.TypeName)
if !isTypeName {
return nil, fmt.Errorf("%s is not a TypeName", object.Name())
}
namedType, isNamedType := typeName.Type().(*types.Named)
if !isNamedType {
return nil, fmt.Errorf("%s is not a named type", object.Name())
}

return namedType, nil
}

func structAttributes(typesInfo *types.Info, structType *ast.StructType) []Attribute {
attributes := make([]Attribute, len(structType.Fields.List))

Expand All @@ -59,3 +91,44 @@ func structAttributes(typesInfo *types.Info, structType *ast.StructType) []Attri

return attributes
}

func structMethods(namedType *types.Named) ([]Method, error) {
methods := make([]Method, namedType.NumMethods())

for i := 0; i < namedType.NumMethods(); i++ {
declaration := namedType.Method(i)
signature, isSignature := declaration.Type().(*types.Signature)
if !isSignature {
return nil, fmt.Errorf("cannot get signature from method %s", declaration.Name())
}

params := []Type{}
if signature.Params() != nil {
params = make([]Type, signature.Params().Len())
for j := 0; j < signature.Params().Len(); j++ {
params[j] = Type(signature.Params().At(j).Type().String())
}
}

returns := []Type{}
if signature.Results() != nil {
returns = make([]Type, signature.Results().Len())
for j := 0; j < signature.Results().Len(); j++ {
returns[j] = Type(signature.Results().At(j).Type().String())
}
}

_, isPointerReceiver := signature.Recv().Type().(*types.Pointer)

methods[i] = Method{
Name: declaration.Name(),
IsExported: declaration.Exported(),
IsPointerReceiver: isPointerReceiver,
Params: params,
Returns: returns,
Comments: []string{}, // TODO
}
}

return methods, nil
}
110 changes: 105 additions & 5 deletions internal/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestParseSuccess(t *testing.T) {
"basic struct": {
goCode: `
package main
type A struct {}
`,
structName: "A",
Expand All @@ -32,7 +32,7 @@ func TestParseSuccess(t *testing.T) {
"struct with one attribute": {
goCode: `
package main
type A struct {
foo string
}
Expand All @@ -52,7 +52,7 @@ func TestParseSuccess(t *testing.T) {
"struct with two attributes": {
goCode: `
package main
type A struct {
foo string
bar uint
Expand All @@ -78,7 +78,7 @@ func TestParseSuccess(t *testing.T) {
"attribute with doc": {
goCode: `
package main
type A struct {
//comment 1
//comment 2
Expand All @@ -100,7 +100,7 @@ func TestParseSuccess(t *testing.T) {
"attribute with inline comment": {
goCode: `
package main
type A struct {
foo string // foo
}
Expand All @@ -117,6 +117,106 @@ func TestParseSuccess(t *testing.T) {
},
},
},
"one empty method, value receiver": {
goCode: `
package main
type A struct {}
func (a A) foo() {}
`,
structName: "A",
expectedStruct: parser.Struct{
Type: parser.Type("A"),
Attributes: []parser.Attribute{},
Methods: []parser.Method{
{
Name: "foo",
IsExported: false,
IsPointerReceiver: false,
Params: []parser.Type{},
Returns: []parser.Type{},
Comments: []string{},
},
},
},
},
"one empty method, pointer receiver": {
goCode: `
package main
type A struct {}
func (a *A) foo() {}
`,
structName: "A",
expectedStruct: parser.Struct{
Type: parser.Type("A"),
Attributes: []parser.Attribute{},
Methods: []parser.Method{
{
Name: "foo",
IsExported: false,
IsPointerReceiver: true,
Params: []parser.Type{},
Returns: []parser.Type{},
Comments: []string{},
},
},
},
},
"one method with 1 param and 1 return, value receiver": {
goCode: `
package main
type A struct {}
func (a A) foo(a string) int {
return 0
}
`,
structName: "A",
expectedStruct: parser.Struct{
Type: parser.Type("A"),
Attributes: []parser.Attribute{},
Methods: []parser.Method{
{
Name: "foo",
IsExported: false,
IsPointerReceiver: false,
Params: []parser.Type{"string"},
Returns: []parser.Type{"int"},
Comments: []string{},
},
},
},
},
"one exported method with 2 params and 2 returns, pointer receiver": {
goCode: `
package main
type A struct {}
func (a *A) Foo(a string, b uint) (int, error) {
return 0
}
`,
structName: "A",
expectedStruct: parser.Struct{
Type: parser.Type("A"),
Attributes: []parser.Attribute{},
Methods: []parser.Method{
{
Name: "Foo",
IsExported: true,
IsPointerReceiver: true,
Params: []parser.Type{"string", "uint"},
Returns: []parser.Type{"int", "error"},
Comments: []string{},
},
},
},
},
}

for name, tc := range testCases {
Expand Down

0 comments on commit 8b3796a

Please sign in to comment.