首页 > 解决方案 > ast.Inspect 不行走 *ast.UnaryExpr

问题描述

我正在尝试检查 Go 源代码以制作工具。为此,我正在使用该ast.Inspect功能。

我需要知道如何在函数/方法中使用通道。

我将此作为示例代码进行检查:

package main

func B(ch chan int) {
    for x := range ch {

    }
}

这是函数 B 的 AST:

 0  *ast.FuncDecl {
     1  .  Name: *ast.Ident {
     2  .  .  NamePos: -:4:6
     3  .  .  Name: "B"
     4  .  .  Obj: *ast.Object {
     5  .  .  .  Kind: func
     6  .  .  .  Name: "B"
     7  .  .  .  Decl: *(obj @ 0)
     8  .  .  }
     9  .  }
    10  .  Type: *ast.FuncType {
    11  .  .  Func: -:4:1
    12  .  .  Params: *ast.FieldList {
    13  .  .  .  Opening: -:4:7
    14  .  .  .  List: []*ast.Field (len = 1) {
    15  .  .  .  .  0: *ast.Field {
    16  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
    17  .  .  .  .  .  .  0: *ast.Ident {
    18  .  .  .  .  .  .  .  NamePos: -:4:8
    19  .  .  .  .  .  .  .  Name: "ch"
    20  .  .  .  .  .  .  .  Obj: *ast.Object {
    21  .  .  .  .  .  .  .  .  Kind: var
    22  .  .  .  .  .  .  .  .  Name: "ch"
    23  .  .  .  .  .  .  .  .  Decl: *(obj @ 15)
    24  .  .  .  .  .  .  .  }
    25  .  .  .  .  .  .  }
    26  .  .  .  .  .  }
    27  .  .  .  .  .  Type: *ast.ChanType {
    28  .  .  .  .  .  .  Begin: -:4:11
    29  .  .  .  .  .  .  Arrow: -
    30  .  .  .  .  .  .  Dir: 3
    31  .  .  .  .  .  .  Value: *ast.Ident {
    32  .  .  .  .  .  .  .  NamePos: -:4:16
    33  .  .  .  .  .  .  .  Name: "int"
    34  .  .  .  .  .  .  }
    35  .  .  .  .  .  }
    36  .  .  .  .  }
    37  .  .  .  }
    38  .  .  .  Closing: -:4:19
    39  .  .  }
    40  .  }
    41  .  Body: *ast.BlockStmt {
    42  .  .  Lbrace: -:4:21
    43  .  .  List: []ast.Stmt (len = 1) {
    44  .  .  .  0: *ast.RangeStmt {
    45  .  .  .  .  For: -:5:2
    46  .  .  .  .  Key: *ast.Ident {
    47  .  .  .  .  .  NamePos: -:5:6
    48  .  .  .  .  .  Name: "x"
    49  .  .  .  .  .  Obj: *ast.Object {
    50  .  .  .  .  .  .  Kind: var
    51  .  .  .  .  .  .  Name: "x"
    52  .  .  .  .  .  .  Decl: *ast.AssignStmt {
    53  .  .  .  .  .  .  .  Lhs: []ast.Expr (len = 1) {
    54  .  .  .  .  .  .  .  .  0: *(obj @ 46)
    55  .  .  .  .  .  .  .  }
    56  .  .  .  .  .  .  .  TokPos: -:5:8
    57  .  .  .  .  .  .  .  Tok: :=
    58  .  .  .  .  .  .  .  Rhs: []ast.Expr (len = 1) {
    59  .  .  .  .  .  .  .  .  0: *ast.UnaryExpr {
    60  .  .  .  .  .  .  .  .  .  OpPos: -:5:11
    61  .  .  .  .  .  .  .  .  .  Op: range
    62  .  .  .  .  .  .  .  .  .  X: *ast.Ident {
    63  .  .  .  .  .  .  .  .  .  .  NamePos: -:5:17
    64  .  .  .  .  .  .  .  .  .  .  Name: "ch"
    65  .  .  .  .  .  .  .  .  .  .  Obj: *(obj @ 20)
    66  .  .  .  .  .  .  .  .  .  }
    67  .  .  .  .  .  .  .  .  }
    68  .  .  .  .  .  .  .  }
    69  .  .  .  .  .  .  }
    70  .  .  .  .  .  }
    71  .  .  .  .  }
    72  .  .  .  .  TokPos: -:5:8
    73  .  .  .  .  Tok: :=
    74  .  .  .  .  X: *(obj @ 62)
    75  .  .  .  .  Body: *ast.BlockStmt {
    76  .  .  .  .  .  Lbrace: -:5:20
    77  .  .  .  .  .  Rbrace: -:7:2
    78  .  .  .  .  }
    79  .  .  .  }
    80  .  .  }
    81  .  .  Rbrace: -:8:1
    82  .

正如您在行中看到的,59我们可以看到有一个设置为 的UnaryExpr节点。这就是我要捕获的节点。Oprange

我尝试使用这段代码走在最前面,只抓住那个节点。

exampleFunc := `
package main

func B(ch chan int) {
    for x := range ch {

    }
}
`
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "-", exampleFunc, parser.ParseComments)
ast.Inspect(file, func(node ast.Node) bool {
    fn, ok := node.(*ast.UnaryExpr) // try to cast
    if !ok {
        return true
    }
        ast.Print(fset, fn)
    return true
})

但这似乎不起作用。

知道为什么,打印整个 FuncDecl 的 AST,我可以看到有一个 UnaryExpr 节点,但是在尝试获取该节点时什么都没有出现?

标签: goabstract-syntax-tree

解决方案


作为@mkopriva,*ast.Ident节点被视为叶子。因此,我们需要手动从RangeStmtto移动AssignStmt(如果有的话),然后再次使用 inspect 到达UnaryExpr


推荐阅读