func (this *astEquals) Check(params []interface{}, names []string) (bool, string) { var obtainedNodes, expectedNodes chan *NodeWithBreadcrumbs var obtainedNode, expectedNode *NodeWithBreadcrumbs obtainedNodes = make(chan *NodeWithBreadcrumbs) expectedNodes = make(chan *NodeWithBreadcrumbs) go ast.Walk(&AstChannelWalker{Out: obtainedNodes}, params[0].(ast.Node)) go ast.Walk(&AstChannelWalker{Out: expectedNodes}, params[1].(ast.Node)) for { obtainedNode = <-obtainedNodes expectedNode = <-expectedNodes if obtainedNode == nil && expectedNode == nil { break } if obtainedNode == nil || expectedNode == nil { return false, fmt.Sprintf("\n%+v\ndid not match\n%+v", obtainedNode, expectedNode) } if !this.nodeEquals(obtainedNode.Node, expectedNode.Node) { return false, fmt.Sprintf("\n%+v\ndid not match\n%+v", obtainedNode, expectedNode) } } return true, "" }
func (v *visitor) Visit(node ast.Node) ast.Visitor { switch node := node.(type) { case *ast.Ident: v.use(v.pkg.Info.Uses[node]) case *ast.ValueSpec: if !v.insideFunc { for _, ident := range node.Names { if !isReserved(ident.Name) { v.decl(v.pkg.Info.Defs[ident]) } } } for _, val := range node.Values { ast.Walk(v, val) } return nil case *ast.FuncDecl: if node.Body != nil { v.insideFunc = true ast.Walk(v, node.Body) v.insideFunc = false } return nil } return v }
func (p *Parser) Parse(fname string, isDir bool) error { var err error if p.PkgPath, err = getPkgPath(fname, isDir); err != nil { return err } fset := token.NewFileSet() if isDir { packages, err := parser.ParseDir(fset, fname, nil, parser.ParseComments) if err != nil { return err } for _, pckg := range packages { ast.Walk(&visitor{Parser: p}, pckg) } } else { f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments) if err != nil { return err } ast.Walk(&visitor{Parser: p}, f) } return nil }
func (x *Indexer) visitSpec(kind SpotKind, spec ast.Spec) { switch n := spec.(type) { case *ast.ImportSpec: x.visitIdent(ImportDecl, n.Name) if n.Path != nil { if imp, err := strconv.Unquote(n.Path.Value); err == nil { x.importCount[x.intern(imp)]++ } } case *ast.AliasSpec: x.visitIdent(kind, n.Name) ast.Walk(x, n.Orig) case *ast.ValueSpec: for _, n := range n.Names { x.visitIdent(kind, n) } ast.Walk(x, n.Type) for _, v := range n.Values { ast.Walk(x, v) } case *ast.TypeSpec: x.visitIdent(TypeDecl, n.Name) ast.Walk(x, n.Type) } }
// Visits files for used nodes. func (p *Package) Visit(node ast.Node) ast.Visitor { u := usedWalker(*p) // hopefully p fields are references. switch n := node.(type) { // don't walk whole file, but only: case *ast.ValueSpec: // - variable initializers for _, value := range n.Values { ast.Walk(&u, value) } // variable types. if n.Type != nil { ast.Walk(&u, n.Type) } case *ast.BlockStmt: // - function bodies for _, stmt := range n.List { ast.Walk(&u, stmt) } case *ast.FuncDecl: // - function signatures ast.Walk(&u, n.Type) case *ast.TypeSpec: // - type declarations ast.Walk(&u, n.Type) } return p }
// rewriteOptionalMethods makes specific mutations to marshaller methods that belong to types identified // as being "optional" (they may be nil on the wire). This allows protobuf to serialize a map or slice and // properly discriminate between empty and nil (which is not possible in protobuf). // TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181 // has agreement func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) { switch t := decl.(type) { case *ast.FuncDecl: ident, ptr, ok := receiver(t) if !ok { return } // correct initialization of the form `m.Field = &OptionalType{}` to // `m.Field = OptionalType{}` if t.Name.Name == "Unmarshal" { ast.Walk(optionalAssignmentVisitor{fn: isOptional}, t.Body) } if !isOptional(ident.Name) { return } switch t.Name.Name { case "Unmarshal": ast.Walk(&optionalItemsVisitor{}, t.Body) case "MarshalTo", "Size", "String": ast.Walk(&optionalItemsVisitor{}, t.Body) fallthrough case "Marshal": // if the method has a pointer receiver, set it back to a normal receiver if ptr { t.Recv.List[0].Type = ident } } } }
func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) { switch n := spec.(type) { case *ast.ImportSpec: x.visitComment(n.Doc) x.visitIdent(ImportDecl, n.Name) ast.Walk(x, n.Path) x.visitComment(n.Comment) case *ast.ValueSpec: x.visitComment(n.Doc) kind := ConstDecl if isVarDecl { kind = VarDecl } for _, n := range n.Names { x.visitIdent(kind, n) } ast.Walk(x, n.Type) for _, v := range n.Values { ast.Walk(x, v) } x.visitComment(n.Comment) case *ast.TypeSpec: x.visitComment(n.Doc) x.visitIdent(TypeDecl, n.Name) ast.Walk(x, n.Type) x.visitComment(n.Comment) } }
// Visits files for used nodes. func (p *Package) Visit(node ast.Node) ast.Visitor { u := usedWalker(*p) // hopefully p fields are references. switch n := node.(type) { // don't walk whole file, but only: case *ast.ValueSpec: // - variable initializers for _, value := range n.Values { ast.Walk(&u, value) } // variable types. if n.Type != nil { ast.Walk(&u, n.Type) } case *ast.BlockStmt: // - function bodies for _, stmt := range n.List { ast.Walk(&u, stmt) } case *ast.FuncDecl: // - function signatures if *includeTests { // Test* functions are always used if strings.HasPrefix(n.Name.String(), "Test") { u.used[n.Name.String()] = true } } ast.Walk(&u, n.Type) case *ast.TypeSpec: // - type declarations ast.Walk(&u, n.Type) } return p }
func instrument(pkg, shortName, fullName string, fset *token.FileSet, parsedFile *ast.File, info *types.Info, out io.Writer, lits map[Literal]struct{}, blocks *[]CoverBlock, sonar *[]CoverBlock) { file := &File{ fset: fset, pkg: pkg, shortName: shortName, fullName: fullName, astFile: parsedFile, blocks: blocks, info: info, } file.addImport("github.com/dvyukov/go-fuzz/go-fuzz-dep", fuzzdepPkg, "Main") if lits != nil { ast.Walk(&LiteralCollector{lits}, file.astFile) } ast.Walk(file, file.astFile) if sonar != nil { s := &Sonar{ fset: fset, shortName: shortName, fullName: fullName, pkg: pkg, blocks: sonar, info: info, } ast.Walk(s, file.astFile) } file.print(out) }
func restoreIdentMapping(oldFile, newFile *ast.File, identMap st.IdentifierMap) { comm := make(chan *ast.Ident) source := &restoreIMSourceVisitor{comm} dest := &restoreIMDestVisitor{identMap, comm} go ast.Walk(source, oldFile) ast.Walk(dest, newFile) }
func main() { goopt.Parse(func() []string { return nil }) if len(goopt.Args) > 0 { x, err := parser.ParseFiles(myfiles, goopt.Args, 0) die(err) fmt.Fprintln(os.Stderr, "Parsed: ", *x["main"]) die(typechecker.CheckPackage(myfiles, x["main"], nil)) fmt.Fprintln(os.Stderr, "Checked: ", *x["main"]) //for _,a := range x["main"].Files { // die(printer.Fprint(os.Stdout, a)) //} aaa := x86.StartData var bbb *Stack var cv = CompileVisitor{&aaa, make(map[string]string), bbb.New("global")} ast.Walk(StringVisitor(cv), x["main"]) cv.Append(x86.StartText...) ast.Walk(&cv, x["main"]) // Here we just add a crude debug library cv.Append(x86.Debugging...) ass := x86.Assembly(*cv.assembly) //fmt.Println(ass) die(elf.AssembleAndLink(goopt.Args[0][:len(goopt.Args[0])-3], []byte(ass))) } }
func trans(pks map[string]*ast.Package) { ts := Trans{} for _, pk := range pks { ast.Walk(normalizer{}, pk) ast.Walk(ts, pk) } fmt.Println("main();") }
// Trim trims the AST rooted at node based on the coverage profile, // removing irrelevant and unreached parts of the program. // If the node is an *ast.File, comments are updated as well using // an ast.CommentMap. func (p *Profile) Trim(node ast.Node) { if f, ok := node.(*ast.File); ok { cmap := ast.NewCommentMap(p.Fset, f, f.Comments) ast.Walk(&trimVisitor{p}, f) f.Comments = cmap.Filter(f).Comments() } else { ast.Walk(&trimVisitor{p}, node) } }
func (vis *pointerCandidatesVisitor) Visit(node ast.Node) ast.Visitor { switch t := node.(type) { case *ast.AssignStmt: for _, expr := range t.Rhs { ast.Walk(vis, expr) } if t.Tok == token.DEFINE { return nil } for _, ee := range t.Lhs { depth := 1 stop := false for !stop { fmt.Printf("%T\n", ee) switch e := ee.(type) { case *ast.Ident: s := vis.identMap.GetSymbol(e) if vis.params.Contains(s) && depth > 0 { if i, ok := vis.result[s]; !ok || i < depth { vis.result[s] = depth } } stop = true case *ast.StarExpr: depth-- ee = e.X case *ast.UnaryExpr: if e.Op == token.AND { depth++ } ee = e.X case *ast.ParenExpr: ee = e.X case *ast.IndexExpr: ast.Walk(vis, e.Index) stop = true case *ast.SelectorExpr: ast.Walk(vis, e.X) stop = true default: stop = true } } } return nil case *ast.UnaryExpr: if t.Op != token.AND { return vis } vis.checkAddrOperators(t) return nil case *ast.StarExpr: vis.checkAddrOperators(t) return nil } return vis }
func compareTwoTrees(src string) { v1 := &channelPusher{} v1.fileSet = token.NewFileSet() v1.queue = make(chan *ast.Node) v2 := &channelPusher{} v2.fileSet = token.NewFileSet() v2.queue = make(chan *ast.Node) tree1, err := parser.ParseExpr(src) if err != nil { panic(err) } src2 := "x + 2*y" tree2, err := parser.ParseExpr(src2) if err != nil { panic(err) } done := make(chan struct{}) defer close(done) go func() { ast.Walk(v1, tree1) close(v1.queue) done <- struct{}{} }() go func() { ast.Walk(v2, tree2) close(v2.queue) done <- struct{}{} }() var n1, n2 *ast.Node quit := false for !quit { select { case n1 = <-v1.queue: case n2 = <-v2.queue: case <-done: quit = true } if n1 != nil && n2 != nil { if !equalNodes(n1, n2) { println("!equalNodes") break } println("equalNodes") n1 = nil n2 = nil } } }
func (v *idVisitor) Visit(n ast.Node) (w ast.Visitor) { switch node := n.(type) { case *ast.Ident, *ast.SelectorExpr: id, err := str(node.(ast.Expr)) if err == nil { v.rIDs[id] = n } case *ast.StarExpr: ast.Walk(v, node.X) return nil case *ast.CallExpr: stmt, ok := node.Fun.(*ast.SelectorExpr) if ok { ast.Walk(v, stmt.X) } if node.Args == nil { return nil } for _, arg := range node.Args { ast.Walk(v, arg) } return nil case *ast.AssignStmt: for _, e := range node.Lhs { id, err := str(e) if err != nil { return } v.wIDs[id] = n } for _, e := range node.Rhs { ast.Walk(v, e) } return nil case *ast.GenDecl: for _, s := range node.Specs { val, ok := s.(*ast.ValueSpec) if !ok { continue } for _, n := range val.Names { id, _ := str(n) v.wIDs[id] = node } } } w = v return }
func (x *Indexer) Visit(node ast.Node) ast.Visitor { switch n := node.(type) { case nil: // nothing to do case *ast.Ident: x.visitIdent(Use, n) case *ast.FieldList: x.visitFieldList(VarDecl, n) case *ast.InterfaceType: x.visitFieldList(MethodDecl, n.Methods) case *ast.DeclStmt: // local declarations should only be *ast.GenDecls; // ignore incorrect ASTs if decl, ok := n.Decl.(*ast.GenDecl); ok { x.decl = nil // no snippets for local declarations x.visitGenDecl(decl) } case *ast.GenDecl: x.decl = n x.visitGenDecl(n) case *ast.FuncDecl: kind := FuncDecl if n.Recv != nil { kind = MethodDecl ast.Walk(x, n.Recv) } x.decl = n x.visitIdent(kind, n.Name) ast.Walk(x, n.Type) if n.Body != nil { ast.Walk(x, n.Body) } case *ast.File: x.decl = nil x.visitIdent(PackageClause, n.Name) for _, d := range n.Decls { ast.Walk(x, d) } default: return x } return nil }
func main() { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "simple.go", nil, 0) if err != nil { // Whoops! } ast.Walk(new(FuncVisitor), file) printer.Fprint(os.Stdout, fset, file) fmt.Println("-------------------------------------") ast.Walk(new(ImportVisitor), file) printer.Fprint(os.Stdout, fset, file) f, _ := os.Create("/tmp/new_simple.go") printer.Fprint(f, fset, file) }
func (v visitor) scanDir(dirPath string) { dir, err := os.Open(dirPath) if err != nil { logFatal(err) } defer dir.Close() names, err := dir.Readdirnames(-1) if err != nil { logFatal(err) } for _, name := range names { fullPath := path.Join(dirPath, name) fi, err := os.Stat(fullPath) if err != nil { logFatal(err) } if fi.IsDir() { v.scanDir(fullPath) } else if !fi.IsDir() && strings.HasSuffix(fullPath, ".go") { astFile, err := parser.ParseFile(v.fileSet, fullPath, nil, 0) if err != nil { logFatal(err) } ast.Walk(v, astFile) } } }
// process parses and rewrites a file by generating the appropriate exported // types for raw types. func process(path string) error { b, err := ioutil.ReadFile(path) if err != nil { return err } // Remove code between begin/end pragma comments. b = regexp.MustCompile(`(?is)//raw:codegen:begin.+?//raw:codegen:end`).ReplaceAll(b, []byte{}) b = []byte(strings.TrimRight(string(b), " \n\r")) // Re-parse the file without the pragmas. f, err := parser.ParseFile(token.NewFileSet(), path, b, 0) if err != nil { return err } // Iterate over all the nodes and add exported types where appropriate. var g generator g.w.Write(b) g.w.WriteString("\n\n") ast.Walk(&g, f) if g.err != nil { return g.err } // Rewrite original file. ioutil.WriteFile(path, g.w.Bytes(), 0600) log.Println("OK", path) return nil }
func Transform(src *ast.File) *ast.File { // find the golex import... var toplevel ToplevelVisitor for _, spec := range src.Imports { ast.Print(nil, spec) if conv, err := strconv.Unquote(spec.Path.Value); err != nil || conv != "golex" { continue } if spec.Name != nil { toplevel.golexPackage = spec.Name.Name } else { toplevel.golexPackage = "golex" } break } if toplevel.golexPackage == "" { log.Print("Not a lex input") return src } ast.Walk(&toplevel, src) // Now, find switch statemnts... return src }
func (c *funcContext) translateLoopingStmt(cond string, body *ast.BlockStmt, bodyPrefix, post func(), label string, flatten bool) { prevFlowData := c.flowDatas[""] data := &flowData{ postStmt: post, } if _, ok := c.labelCases[label]; ok { flatten = true // always flatten if label is referenced by goto } if flatten { data.beginCase = c.caseCounter data.endCase = c.caseCounter + 1 c.caseCounter += 2 } c.flowDatas[""] = data c.flowDatas[label] = data c.printLabel(label) if !flatten && label != "" { c.Printf("%s:", label) } c.PrintCond(!flatten, fmt.Sprintf("while (%s) {", cond), fmt.Sprintf("case %d: if(!(%s)) { $s = %d; continue; }", data.beginCase, cond, data.endCase)) c.Indent(func() { v := &escapeAnalysis{ info: c.p.info, candidates: make(map[types.Object]bool), escaping: make(map[types.Object]bool), } ast.Walk(v, body) prevEV := c.p.escapingVars c.p.escapingVars = make(map[types.Object]bool) for escaping := range prevEV { c.p.escapingVars[escaping] = true } for escaping := range v.escaping { c.Printf("%s = [undefined];", c.objectName(escaping)) c.p.escapingVars[escaping] = true } if bodyPrefix != nil { bodyPrefix() } c.translateStmtList(body.List) isTerminated := false if len(body.List) != 0 { switch body.List[len(body.List)-1].(type) { case *ast.ReturnStmt, *ast.BranchStmt: isTerminated = true } } if !isTerminated { post() } c.p.escapingVars = prevEV }) c.PrintCond(!flatten, "}", fmt.Sprintf("$s = %d; continue; case %d:", data.beginCase, data.endCase)) delete(c.flowDatas, label) c.flowDatas[""] = prevFlowData }
func annotate(name string) { fset := token.NewFileSet() content, err := ioutil.ReadFile(name) if err != nil { log.Fatalf("cover: %s: %s", name, err) } parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments) if err != nil { log.Fatalf("cover: %s: %s", name, err) } parsedFile.Comments = trimComments(parsedFile, fset) file := &File{ fset: fset, name: name, astFile: parsedFile, } if *mode == "atomic" { file.atomicPkg = file.addImport(atomicPackagePath) } ast.Walk(file, file.astFile) fd := os.Stdout if *output != "" { var err error fd, err = os.Create(*output) if err != nil { log.Fatalf("cover: %s", err) } } fd.Write(initialComments(content)) // Retain '// +build' directives. file.print(fd) // After printing the source tree, add some declarations for the counters etc. // We could do this by adding to the tree, but it's easier just to print the text. file.addVariables(fd) }
// UsesImport reports whether a given import is used. func UsesImport(f *ast.File, path string) (used bool) { spec := importSpec(f, path) if spec == nil { return } name := spec.Name.String() switch name { case "<nil>": // If the package name is not explicitly specified, // make an educated guess. This is not guaranteed to be correct. lastSlash := strings.LastIndex(path, "/") if lastSlash == -1 { name = path } else { name = path[lastSlash+1:] } case "_", ".": // Not sure if this import is used - err on the side of caution. return true } ast.Walk(visitFn(func(n ast.Node) { sel, ok := n.(*ast.SelectorExpr) if ok && isTopName(sel.X, name) { used = true } }), f) return }
func checkHTTPResponse(f *File, node ast.Node) { call := node.(*ast.CallExpr) if !isHTTPFuncOrMethodOnClient(f, call) { return // the function call is not related to this check. } finder := &blockStmtFinder{node: call} ast.Walk(finder, f.file) stmts := finder.stmts() if len(stmts) < 2 { return // the call to the http function is the last statement of the block. } asg, ok := stmts[0].(*ast.AssignStmt) if !ok { return // the first statement is not assignment. } resp := rootIdent(asg.Lhs[0]) if resp == nil { return // could not find the http.Response in the assignment. } def, ok := stmts[1].(*ast.DeferStmt) if !ok { return // the following statement is not a defer. } root := rootIdent(def.Call.Fun) if root == nil { return // could not find the receiver of the defer call. } if resp.Obj == root.Obj { f.Badf(root.Pos(), "using %s before checking for errors", resp.Name) } }
func MutateFile(src string, f, t token.Token) error { fset := token.NewFileSet() file, err := parser.ParseFile(fset, src, nil, 0) if err != nil { return fmt.Errorf("failed to parse %s: %s", src, err) } ef := ExpressionFinder{Token: f} ast.Walk(&ef, file) filename := filepath.Base(src) log.Printf("found %d occurrences of %s in %s", ef.Len(), f, filename) for index, exp := range ef.Exps { err := RunMutation(index, exp, f, t, src, fset, file) if err != nil { return err } } // Restore the original file err = printFile(src, fset, file) if err != nil { return err } return nil }
func simplify(f *ast.File) { // remove empty declarations such as "const ()", etc removeEmptyDeclGroups(f) var s simplifier ast.Walk(s, f) }
func (gas *Analyzer) process(filename string, source interface{}) error { mode := parser.ParseComments root, err := parser.ParseFile(gas.context.FileSet, filename, source, mode) if err == nil { gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, root, root.Comments) gas.context.Root = root // here we get type info gas.context.Info = &types.Info{ Types: make(map[ast.Expr]types.TypeAndValue), Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), Scopes: make(map[ast.Node]*types.Scope), Implicits: make(map[ast.Node]types.Object), } conf := types.Config{Importer: importer.Default()} gas.context.Pkg, _ = conf.Check("pkg", gas.context.FileSet, []*ast.File{root}, gas.context.Info) if err != nil { gas.logger.Println("failed to check imports") return err } ast.Walk(gas, root) gas.Stats.NumFiles++ } return err }
func GetDeps(source string) (pkg, target string, deps, funcs, cflags, ldflags []string, err error) { isTest := strings.HasSuffix(source, "_test.go") && Test var file *ast.File flag := parser.ParseComments if !isTest { flag = flag | parser.ImportsOnly } file, err = parser.ParseFile(token.NewFileSet(), source, nil, flag) if err != nil { return } w := &Walker{ Name: "", Target: "", pkgPos: 0, Deps: []string{}, Funcs: []string{}, CGoLDFlags: []string{}, CGoCFlags: []string{}, ScanFuncs: isTest, } ast.Walk(w, file) deps = w.Deps pkg = w.Name target = w.Target funcs = w.Funcs cflags = RemoveDups(w.CGoCFlags) ldflags = RemoveDups(w.CGoLDFlags) return }
func (f *File) methodSet(set *types.MethodSet) { // Build the set of things we're looking for. methods := make([]method, 0, set.Len()) docs := make([]string, set.Len()) for i := 0; i < set.Len(); i++ { if ast.IsExported(set.At(i).Obj().Name()) { m := method{ i, set.At(i), } methods = append(methods, m) } } if len(methods) == 0 { return } // Collect the docs. for _, file := range f.allFiles { visitor := &methodVisitor{ File: file, methods: methods, docs: docs, } ast.Walk(visitor, file.file) methods = visitor.methods } // Print them in order. The incoming method set is sorted by name. for _, doc := range docs { if doc != "" { fmt.Print(doc) } } }