【问题标题】:Use ast to get all function calls in a function使用 ast 获取函数中的所有函数调用
【发布时间】:2018-02-27 02:17:21
【问题描述】:

我正在尝试使用 ast 列出函数中的所有函数调用。但是很难理解它应该如何使用。我已经能够做到这一点。

set := token.NewFileSet()
packs, err := parser.ParseFile(set, serviceFile, nil, 0)
if err != nil {
    fmt.Println("Failed to parse package:", err)
    os.Exit(1)
}

funcs := []*ast.FuncDecl{}
for _, d := range packs.Decls {
    if fn, isFn := d.(*ast.FuncDecl); isFn {
        funcs = append(funcs, fn)
    }
}

我检查了函数。我去funcs[n1].Body.List[n2]。 但在此之后,我不明白我应该如何阅读底层data.X.Fun.data.Sel.name(从 gogland 的评估中获得)以获取被调用函数的名称。

【问题讨论】:

标签: go abstract-syntax-tree


【解决方案1】:

好吧,我发现你必须进行大量转换才能实际提取数据。

这是一个关于如何在 func 中提取 func 调用的示例。

for _, function := range funcs {
    extractFuncCallInFunc(function.Body.List)
}

func extractFuncCallInFunc(stmts []ast.Stmt) {
    for _, stmt := range funcs {
        if exprStmt, ok := stmt.(*ast.ExprStmt); ok {
            if call, ok := exprStmt.X.(*ast.CallExpr); ok {
                if fun, ok := call.Fun.(*ast.SelectorExpr); ok {
                    funcName := fun.Sel.Name
                }
            }
        }
    }
}

我还发现这有助于找出您需要将其投射到什么。 http://goast.yuroyoro.net/

【讨论】:

  • 这不会捕获所有情况。考虑以下表达式:b := a.c()。这将产生一个AssignStmt -> [AssignStmt 的Rhs 成员] -> CallExpr -> SelectorExpr。您的 extractFuncCallInFunc() 会错过这种情况。
  • 另一个例子是b := a.c(d.e),你也会错过d.e 部分。我认为没有一种简单的方法可以在 FuncDelc.Body 中找到所有 SelectorExpr ...
【解决方案2】:

您可以为此使用 ast.Inspect 并使用节点类型的开关。

for _, fun := range funcs {
    ast.Inspect(fun, func(node ast.Node) bool {
        switch n := node.(type) {
            case *ast.CallExpr:
                fmt.Println(n) // prints every func call expression
        }
        return true
    })
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    • 2015-10-22
    • 2011-02-15
    • 2016-10-21
    • 2012-04-07
    相关资源
    最近更新 更多