golang.org/x/tools/gopls@v0.15.3/internal/util/astutil/purge_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package astutil_test 6 7 import ( 8 "go/ast" 9 "go/parser" 10 "go/token" 11 "os" 12 "reflect" 13 "testing" 14 15 "golang.org/x/tools/go/packages" 16 "golang.org/x/tools/gopls/internal/util/astutil" 17 "golang.org/x/tools/internal/testenv" 18 ) 19 20 // TestPurgeFuncBodies tests PurgeFuncBodies by comparing it against a 21 // (less efficient) reference implementation that purges after parsing. 22 func TestPurgeFuncBodies(t *testing.T) { 23 testenv.NeedsGoBuild(t) // we need the source code for std 24 25 // Load a few standard packages. 26 config := packages.Config{Mode: packages.NeedCompiledGoFiles} 27 pkgs, err := packages.Load(&config, "encoding/...") 28 if err != nil { 29 t.Fatal(err) 30 } 31 32 // preorder returns the nodes of tree f in preorder. 33 preorder := func(f *ast.File) (nodes []ast.Node) { 34 ast.Inspect(f, func(n ast.Node) bool { 35 if n != nil { 36 nodes = append(nodes, n) 37 } 38 return true 39 }) 40 return nodes 41 } 42 43 packages.Visit(pkgs, nil, func(p *packages.Package) { 44 for _, filename := range p.CompiledGoFiles { 45 content, err := os.ReadFile(filename) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 fset := token.NewFileSet() 51 52 // Parse then purge (reference implementation). 53 f1, _ := parser.ParseFile(fset, filename, content, 0) 54 ast.Inspect(f1, func(n ast.Node) bool { 55 switch n := n.(type) { 56 case *ast.FuncDecl: 57 if n.Body != nil { 58 n.Body.List = nil 59 } 60 case *ast.FuncLit: 61 n.Body.List = nil 62 case *ast.CompositeLit: 63 n.Elts = nil 64 } 65 return true 66 }) 67 68 // Purge before parse (logic under test). 69 f2, _ := parser.ParseFile(fset, filename, astutil.PurgeFuncBodies(content), 0) 70 71 // Compare sequence of node types. 72 nodes1 := preorder(f1) 73 nodes2 := preorder(f2) 74 if len(nodes2) < len(nodes1) { 75 t.Errorf("purged file has fewer nodes: %d vs %d", 76 len(nodes2), len(nodes1)) 77 nodes1 = nodes1[:len(nodes2)] // truncate 78 } 79 for i := range nodes1 { 80 x, y := nodes1[i], nodes2[i] 81 if reflect.TypeOf(x) != reflect.TypeOf(y) { 82 t.Errorf("%s: got %T, want %T", 83 fset.Position(x.Pos()), y, x) 84 break 85 } 86 } 87 } 88 }) 89 }