I want to extract signatures of functions to be able generate some wrapper methods over them. For this, I'm using
golang.org/x/tools/go/packages
which provides me a possibility to read AST.
For example, for the function func MyFunc(param int)
definition, you receive some
ast.FuncDecl{
Type: *FieldList{
List: []*Field{
{
Names: []*Ident{ /*...*/ },
Type: nil, /*...*/
},
},
},
}
Where Type represents a type.
I want to generate some special code for all int
parameters, but int can be also hidden with some type declaration
type MyType int
How can I convert ast
type to the real one that the compiler has?
Add packages.NeedTypes
and packages.NeedTypesInfo
to the load mode. With that each loaded package will have its TypesInfo
field initialized, and that field's type *types.Info
has a field called Types
which maps ast expressions to types. You can use that in the following way:
func main() {
loadConfig := new(packages.Config)
loadConfig.Mode = packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo
loadConfig.Fset = token.NewFileSet()
pkgs, err := packages.Load(loadConfig, "syscall")
if err != nil {
panic(err)
}
for _, pkg := range pkgs {
for _, syn := range pkg.Syntax {
for _, dec := range syn.Decls {
if fd, ok := dec.(*ast.FuncDecl); ok && fd.Name.Name == "Kill" {
x1 := fd.Type.Params.List[0].Type // int
x2 := fd.Type.Params.List[1].Type // syscall.Signal
tv1 := pkg.TypesInfo.Types[x1]
tv2 := pkg.TypesInfo.Types[x2]
if basic, ok := tv1.Type.(*types.Basic); ok {
fmt.Printf("%#v\n", basic) // int
}
if named, ok := tv2.Type.(*types.Named); ok {
fmt.Printf("%v\n", named.Obj()) // *types.TypeName (Signal)
fmt.Printf("%#v\n", named.Underlying()) // *types.Basic (int)
}
}
}
}
}
}