Go ast.检查不行走*ast.UnaryExpr
我试图检查Go源代码,以便制作一个工具。为此,我使用了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: *
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
。。。。我考虑过,但你认为这对所有情况都有效吗?我的意思是,通道范围?我不确定,你必须自己测试它,我认为这不太难,因为通道范围表达式没有太多变化。