英文:
Golang static identifier resolution
问题
我正在尝试使用go/parse
、go/token
和go/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() // <- 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: "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 }
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论