Home > Blockchain >  How to resolve types into a primitives in AST parser
How to resolve types into a primitives in AST parser

Time:10-03

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?

CodePudding user response:

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)
                    }
                }
            }
        }
    }
}
  • Related