如何在 AST 解析器中将类型解析为原语

How to resolve types into a primitives in AST parser

我想提取函数的签名以便能够在它们之上生成一些包装方法。为此,我正在使用 golang.org/x/tools/go/packages 这让我有机会阅读 AST。

例如,对于函数func MyFunc(param int)的定义,您收到一些

ast.FuncDecl{
    Type: *FieldList{
        List: []*Field{
            {
                Names: []*Ident{ /*...*/ },
                Type:  nil, /*...*/
            },
        },
    },
}

其中 Type 表示类型。

我想为所有 int 参数生成一些特殊代码,但是 int 也可以用一些类型声明隐藏起来

type MyType int

如何将 ast 类型转换为编译器拥有的真实类型?

添加 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 将 ast 表达式映射到类型。您可以通过以下方式使用它:

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