Golang静态标识符解析

huangapple go评论89阅读模式
英文:

Golang static identifier resolution

问题

我正在尝试使用go/parsego/tokengo/ast模块对Go项目中的函数调用进行静态分析,但我无法确定如何确定给定ast.Ident对象的类型。

例如,如果解析以下内容:

textToContain := bytes.NewBuffer([]byte{})
// 其他大量代码
text := textToContain.String() // <- 我关心这个函数调用

(这是从这里解析的:file

编辑:解析这个需要很多代码,所以我没有在这里发布,但你可以在这里找到它的gist:https://gist.github.com/EricChiang/6735340c5fa3d2de2b73

我使用ast.Print函数打印出以下代码:

 0  *ast.CallExpr {
 1  .  Fun: *ast.SelectorExpr {
 2  .  .  X: *ast.Ident {
 4  .  .  .  Name: "textToContain"
 5  .  .  .  Obj: *ast.Object {
 6  .  .  .  .  Kind: var
 7  .  .  .  .  Name: "textToContain"
 8  .  .  .  .  Decl: *ast.AssignStmt {
 9  .  .  .  .  .  Lhs: []ast.Expr (len = 1) {
10  .  .  .  .  .  .  0: *ast.Ident {
12  .  .  .  .  .  .  .  Name: "textToContain"
13  .  .  .  .  .  .  .  Obj: *(obj @ 5)
14  .  .  .  .  .  .  }
15  .  .  .  .  .  }
17  .  .  .  .  .  Tok: :=
18  .  .  .  .  .  Rhs: []ast.Expr (len = 1) {
19  .  .  .  .  .  .  0: *ast.CallExpr {
20  .  .  .  .  .  .  .  Fun: *ast.SelectorExpr {
21  .  .  .  .  .  .  .  .  X: *ast.Ident {
23  .  .  .  .  .  .  .  .  .  Name: "bytes"
24  .  .  .  .  .  .  .  .  }
25  .  .  .  .  .  .  .  .  Sel: *ast.Ident {
27  .  .  .  .  .  .  .  .  .  Name: "NewBuffer"
28  .  .  .  .  .  .  .  .  }
29  .  .  .  .  .  .  .  }
31  .  .  .  .  .  .  .  Args: []ast.Expr (len = 1) {
32  .  .  .  .  .  .  .  .  0: *ast.CompositeLit {
33  .  .  .  .  .  .  .  .  .  Type: *ast.ArrayType {
35  .  .  .  .  .  .  .  .  .  .  Elt: *ast.Ident {
37  .  .  .  .  .  .  .  .  .  .  .  Name: "byte"
38  .  .  .  .  .  .  .  .  .  .  }
39  .  .  .  .  .  .  .  .  .  }
42  .  .  .  .  .  .  .  .  }
43  .  .  .  .  .  .  .  }
44  .  .  .  .  .  .  .  Ellipsis: -
46  .  .  .  .  .  .  }
47  .  .  .  .  .  }
48  .  .  .  .  }
49  .  .  .  }
50  .  .  }
51  .  .  Sel: *ast.Ident {
53  .  .  .  Name: "String"
54  .  .  }
55  .  }
57  .  Ellipsis: -
59  }

但我看不到我可以推断出textToContain的类型的地方。

我知道有一堆工具可以做到这一点,例如这个示例来自Go博客,但我觉得我走错了方向。

英文:

I'm attempting to do some static analysis on function calls in a Go project using the go/parse, go/token and go/ast modules, but I can't figure out how to determine the type of a given ast.Ident object.

For instance if parse something like this:

textToContain := bytes.NewBuffer([]byte{})
// lots of other code
text := textToContain.String() // &lt;- I care about this function call

(this is parsed from here: file)

EDIT: It took a lot of code to parse this so I didn't post it here, but you can find it as a gist at: https://gist.github.com/EricChiang/6735340c5fa3d2de2b73

I get the following code printed using the ast.Print function

 0  *ast.CallExpr {
 1  .  Fun: *ast.SelectorExpr {
 2  .  .  X: *ast.Ident {
 4  .  .  .  Name: &quot;textToContain&quot;
 5  .  .  .  Obj: *ast.Object {
 6  .  .  .  .  Kind: var
 7  .  .  .  .  Name: &quot;textToContain&quot;
 8  .  .  .  .  Decl: *ast.AssignStmt {
 9  .  .  .  .  .  Lhs: []ast.Expr (len = 1) {
10  .  .  .  .  .  .  0: *ast.Ident {
12  .  .  .  .  .  .  .  Name: &quot;textToContain&quot;
13  .  .  .  .  .  .  .  Obj: *(obj @ 5)
14  .  .  .  .  .  .  }
15  .  .  .  .  .  }
17  .  .  .  .  .  Tok: :=
18  .  .  .  .  .  Rhs: []ast.Expr (len = 1) {
19  .  .  .  .  .  .  0: *ast.CallExpr {
20  .  .  .  .  .  .  .  Fun: *ast.SelectorExpr {
21  .  .  .  .  .  .  .  .  X: *ast.Ident {
23  .  .  .  .  .  .  .  .  .  Name: &quot;bytes&quot;
24  .  .  .  .  .  .  .  .  }
25  .  .  .  .  .  .  .  .  Sel: *ast.Ident {
27  .  .  .  .  .  .  .  .  .  Name: &quot;NewBuffer&quot;
28  .  .  .  .  .  .  .  .  }
29  .  .  .  .  .  .  .  }
31  .  .  .  .  .  .  .  Args: []ast.Expr (len = 1) {
32  .  .  .  .  .  .  .  .  0: *ast.CompositeLit {
33  .  .  .  .  .  .  .  .  .  Type: *ast.ArrayType {
35  .  .  .  .  .  .  .  .  .  .  Elt: *ast.Ident {
37  .  .  .  .  .  .  .  .  .  .  .  Name: &quot;byte&quot;
38  .  .  .  .  .  .  .  .  .  .  }
39  .  .  .  .  .  .  .  .  .  }
42  .  .  .  .  .  .  .  .  }
43  .  .  .  .  .  .  .  }
44  .  .  .  .  .  .  .  Ellipsis: -
46  .  .  .  .  .  .  }
47  .  .  .  .  .  }
48  .  .  .  .  }
49  .  .  .  }
50  .  .  }
51  .  .  Sel: *ast.Ident {
53  .  .  .  Name: &quot;String&quot;
54  .  .  }
55  .  }
57  .  Ellipsis: -
59  }

But I can't see where I could infer the type of textToContain

I know a bunch of tools that can do this, for instance this example from the go blog, but I think I'm going in the wrong direction.

答案1

得分: 6

3of3是正确的;你需要类型检查器,即golang.org/x/tools/go/types。一般来说,表达式的类型取决于导入依赖的传递闭包的类型信息,所以你可能想使用golang.org/x/tools/go/loader包(我维护的),它会为你处理许多具有挑战性的细节。它的stdlib_test.go可能是一个有用的起点。

一旦你确定了感兴趣的表达式,你可以在AST包的types.Info结构的映射之一中找到它的类型。

在这种情况下,表达式是一个引用标识符(*ast.Ident),所以在Uses映射中查找它所引用的types.Object(命名实体)---在这种情况下是一个局部变量(*types.Var)。对于除标识符以外的表达式,Types映射将告诉你它的类型。

英文:

3of3 is right; you need the type checker, which is golang.org/x/tools/go/types. In general, the type of an expression depends on type information for the transitive closure of import dependencies, so you will probably want to use the golang.org/x/tools/go/loader package (which I maintain), which takes care of many challenging details for you. Its stdlib_test.go may be a useful starting point.

Once you've identified the expression of interest, you can find its type in one of the mappings within the types.Info structure for the AST's package.

In this case, the expression is a referring identifier (*ast.Ident) so look in the Uses mapping to find the types.Object (named entity) to which it refers---a local variable (*types.Var) in this case. For expressions other than identifiers, the Types mapping will tell you its type.

huangapple
  • 本文由 发表于 2015年1月16日 10:39:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/27976493.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定