Go ast.检查不行走*ast.UnaryExpr

Go ast.检查不行走*ast.UnaryExpr,go,abstract-syntax-tree,Go,Abstract Syntax Tree,我试图检查Go源代码,以便制作一个工具。为此,我使用了ast.Inspect函数 我需要知道函数/方法中如何使用通道 我将此作为示例代码进行检查: 主程序包 func B(ch chan int){ 对于x:=范围ch{ } } 这是函数B的AST: 0 *ast.FuncDecl { 1 . Name: *ast.Ident { 2 . . NamePos: -:4:6 3 . . Name: "B" 4 . . Obj: *

我试图检查Go源代码,以便制作一个工具。为此,我使用了
ast.Inspect
函数

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

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

主程序包
func B(ch chan int){
对于x:=范围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
节点,
Op
设置为
range
。这就是我想要捕捉的节点

我尝试使用此代码遍历ast并仅捕获该节点

exampleFunc:=`
包干管
func B(ch chan int){
对于x:=范围ch{
}
}
`
fset:=token.NewFileSet()
file,err:=parser.ParseFile(fset,“-”,exampleFunc,parser.ParseComments)
ast.Inspect(文件,func(节点ast.node)bool{
fn,ok:=节点。(*ast.UnaryExpr)//尝试强制转换
如果!好的{
返回真值
}
ast.打印(fset,fn)
返回真值
})
但它似乎不起作用


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

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

不确定这是否有文档记录,但如果您查看
Walk
的源代码,这就是
inspect
所委托的,您会发现,
Ident
被它视为类似叶节点的东西,即,
Ident
的任何子节点都不会走得更远,至少不会直接穿过
Ident
节点。(源代码中的注释是
无事可做
)。这意味着您需要做更多的工作才能到达所需的节点。例如,您可以手动从
rangesmt
AssignStmt
,然后继续第二次调用
Inspect
,以捕获您的
UnaryExpr
。。。。我考虑过,但你认为这对所有情况都有效吗?我的意思是,通道范围?我不确定,你必须自己测试它,我认为这不太难,因为通道范围表达式没有太多变化。