7

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.

2
  • hard to figure out without some sample code. Commented Jan 16, 2015 at 2:46
  • 2
    @fabrizioM took a lot of code to get here so I refrained from putting it in. you can find a gist here gist.github.com/EricChiang/6735340c5fa3d2de2b73 Commented Jan 16, 2015 at 2:53

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.