parsing - 如何使用 Go 解析方法或函数中的语句

标签 parsing go

我想解析 go 代码,尤其是函数的内容。

到目前为止,使用 parser.ParseFile 函数很容易获得函数声明。

package main

import (
    "fmt"
    "go/parser"
    "go/token"
    "go/ast"
    "log"
)

var code = []byte(`
package main

import (
    "fmt"
)

func GetFoo() {
    test := foo()
    fmt.Println(test)
}

func foo() int {
    return 0
}
`)

func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "", code, parser.ParseComments)
    if err != nil {
        log.Fatal(err)
    }

    for _, decl := range f.Decls {
        switch t := decl.(type) {
        // That's a func decl !
        case *ast.FuncDecl:
            fmt.Printf("Function name: %v\n", t.Name)
            // Now I would like to access to the test var and get its type
            // Must be int, because foo() returns an int
        }
    }

}

现在我想访问 test var 并获取它的类型,但我有点迷路了。我已经看到 decl.Body.List 迭代语句,但我可以得到我的 test var 是一个 int

感谢您宝贵的帮助!

https://play.golang.org/p/Y8uwM-CDWy

最佳答案

感谢JimB以及他关于 go/types 的提示,这是我如何获得我的方法的签名

package main

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
    "log"
)

var code = []byte(`
package main

import (
    "fmt"
)

func GetFoo() {
    test := foo()
    fmt.Println(test)
}

func foo() int {
    return 0
}
`)

func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "", code, parser.ParseComments)
    if err != nil {
        log.Fatal(err)
    }

    conf := types.Config{Importer: importer.Default()}
    pkg, err := conf.Check("cmd", fset, []*ast.File{f}, nil)
    scope := pkg.Scope()

    for _, decl := range f.Decls {
        switch t := decl.(type) {
        // That's a func decl !
        case *ast.FuncDecl:
            for _, s := range t.Body.List {
                switch as := s.(type) {
                case *ast.AssignStmt:
                    for _, l := range as.Rhs {
                        switch rh := l.(type) {
                        case *ast.CallExpr:
                            if i, ok := rh.Fun.(*ast.Ident); ok {
                                ft := scope.Lookup(i.Name)
                                if ft != nil {
                                    if ftype, ok := ft.(*types.Func); ok {
                                        f := ftype.Type()
                                        if sig, ok := f.(*types.Signature); ok {
                                            // get the returned elements
                                            r := sig.Results()
                                            for i := 0; i < r.Len(); i++ {
                                                v := r.At(i)
                                                varTpe := v.Type()
                                                fmt.Println(varTpe)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

关于parsing - 如何使用 Go 解析方法或函数中的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46545594/

相关文章:

去反射(reflection)元编程/模板

go - 如何使用一个字节的缓冲区作为 map 的关键存储?

c# - DateTime.Parse 今天(2012 年 3 月 1 日)失败! o_0

python - 同时抓取太多链接

java - Jsoup child 尺寸值不正确

java - 获取Java源文件的包

go - 哪些数据类型本质上是原子的

c# - 如何设置 DateTime 小时、分钟和秒?

go - 在 GO 中重用数据库连接和 'invalid memory address' 错误

go - 如何从 STDIN 读取 “postpone”