// IterateSyms calls visitf for each identifier in the given file. If // visitf returns false, the iteration stops. If visitf changes // info.Ident.Name, the file is added to ctxt.ChangedFiles. func (ctxt *Context) IterateSyms(f *ast.File, visitf func(info *Info) bool) { var visit astVisitor ok := true local := false // TODO set to true inside function body visit = func(n ast.Node) bool { if !ok { return false } switch n := n.(type) { case *ast.ImportSpec: // If the file imports a package to ".", abort // because we don't support that (yet). if n.Name != nil && n.Name.Name == "." { ctxt.logf(n.Pos(), "import to . not supported") ok = false return false } return true case *ast.FuncDecl: // add object for init functions if n.Recv == nil && n.Name.Name == "init" { n.Name.Obj = ast.NewObj(ast.Fun, "init") } if n.Recv != nil { ast.Walk(visit, n.Recv) } var e ast.Expr = n.Name if n.Recv != nil { // It's a method, so we need to synthesise a // selector expression so that visitExpr doesn't // just see a blank name. if len(n.Recv.List) != 1 { ctxt.logf(n.Pos(), "expected one receiver only!") return true } e = &ast.SelectorExpr{ X: n.Recv.List[0].Type, Sel: n.Name, } } ok = ctxt.visitExpr(f, e, false, visitf) local = true ast.Walk(visit, n.Type) if n.Body != nil { ast.Walk(visit, n.Body) } local = false return false case *ast.Ident: ok = ctxt.visitExpr(f, n, local, visitf) return false case *ast.KeyValueExpr: // don't try to resolve the key part of a key-value // because it might be a map key which doesn't // need resolving, and we can't tell without being // complicated with types. ast.Walk(visit, n.Value) return false case *ast.SelectorExpr: ast.Walk(visit, n.X) ok = ctxt.visitExpr(f, n, local, visitf) return false case *ast.File: for _, d := range n.Decls { ast.Walk(visit, d) } return false } return true } ast.Walk(visit, f) }
func checkExprs(t *testing.T, pkg *ast.File, importer Importer) { var visit astVisitor stopped := false visit = func(n ast.Node) bool { if stopped { return false } mustResolve := false var e ast.Expr switch n := n.(type) { case *ast.ImportSpec: // If the file imports a package to ".", abort // because we don't support that (yet). if n.Name != nil && n.Name.Name == "." { stopped = true return false } return true case *ast.FuncDecl: // add object for init functions if n.Recv == nil && n.Name.Name == "init" { n.Name.Obj = ast.NewObj(ast.Fun, "init") } return true case *ast.Ident: if n.Name == "_" { return false } e = n mustResolve = true case *ast.KeyValueExpr: // don't try to resolve the key part of a key-value // because it might be a map key which doesn't // need resolving, and we can't tell without being // complicated with types. ast.Walk(visit, n.Value) return false case *ast.SelectorExpr: ast.Walk(visit, n.X) e = n mustResolve = true case *ast.File: for _, d := range n.Decls { ast.Walk(visit, d) } return false case ast.Expr: e = n default: return true } defer func() { if err := recover(); err != nil { t.Fatalf("panic (%v) on %T", err, e) //t.Fatalf("panic (%v) on %v at %v\n", err, e, FileSet.Position(e.Pos())) } }() obj, _ := ExprType(e, importer) if obj == nil && mustResolve { t.Errorf("no object for %v(%p, %T) at %v\n", e, e, e, FileSet.Position(e.Pos())) } return false } ast.Walk(visit, pkg) }
func declObj(kind ast.ObjKind, name string) { // don't use Insert because it forbids adding to Universe Universe.Objects[name] = ast.NewObj(kind, name) }