GoPLS Viewer

Home|gopls/internal/gcimporter/shallow_test.go
1// Copyright 2022 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
5package gcimporter_test
6
7import (
8    "fmt"
9    "go/ast"
10    "go/parser"
11    "go/token"
12    "go/types"
13    "testing"
14
15    "golang.org/x/sync/errgroup"
16    "golang.org/x/tools/go/packages"
17    "golang.org/x/tools/internal/gcimporter"
18    "golang.org/x/tools/internal/testenv"
19)
20
21// TestStd type-checks the standard library using shallow export data.
22func TestShallowStd(t *testing.T) {
23    if testing.Short() {
24        t.Skip("skipping in short mode; too slow (https://golang.org/issue/14113)")
25    }
26    testenv.NeedsTool(t"go")
27
28    // Load import graph of the standard library.
29    // (No parsing or type-checking.)
30    cfg := &packages.Config{
31        Modepackages.NeedImports |
32            packages.NeedName |
33            packages.NeedFiles | // see https://github.com/golang/go/issues/56632
34            packages.NeedCompiledGoFiles,
35        Testsfalse,
36    }
37    pkgserr := packages.Load(cfg"std")
38    if err != nil {
39        t.Fatalf("load: %v"err)
40    }
41    if len(pkgs) < 200 {
42        t.Fatalf("too few packages: %d"len(pkgs))
43    }
44
45    // Type check the packages in parallel postorder.
46    done := make(map[*packages.Package]chan struct{})
47    packages.Visit(pkgsnil, func(p *packages.Package) {
48        done[p] = make(chan struct{})
49    })
50    packages.Visit(pkgsnil,
51        func(pkg *packages.Package) {
52            go func() {
53                // Wait for all deps to be done.
54                for _imp := range pkg.Imports {
55                    <-done[imp]
56                }
57                typecheck(tpkg)
58                close(done[pkg])
59            }()
60        })
61    for _root := range pkgs {
62        <-done[root]
63    }
64}
65
66// typecheck reads, parses, and type-checks a package.
67// It squirrels the export data in the the ppkg.ExportFile field.
68func typecheck(t *testing.Tppkg *packages.Package) {
69    if ppkg.PkgPath == "unsafe" {
70        return // unsafe is special
71    }
72
73    // Create a local FileSet just for this package.
74    fset := token.NewFileSet()
75
76    // Parse files in parallel.
77    syntax := make([]*ast.Filelen(ppkg.CompiledGoFiles))
78    var group errgroup.Group
79    for ifilename := range ppkg.CompiledGoFiles {
80        ifilename := ifilename
81        group.Go(func() error {
82            ferr := parser.ParseFile(fsetfilenamenilparser.SkipObjectResolution)
83            if err != nil {
84                return err // e.g. missing file
85            }
86            syntax[i] = f
87            return nil
88        })
89    }
90    if err := group.Wait(); err != nil {
91        t.Fatal(err)
92    }
93    // Inv: all files were successfully parsed.
94
95    // Build map of dependencies by package path.
96    // (We don't compute this mapping for the entire
97    // packages graph because it is not globally consistent.)
98    depsByPkgPath := make(map[string]*packages.Package)
99    {
100        var visit func(*packages.Package)
101        visit = func(pkg *packages.Package) {
102            if depsByPkgPath[pkg.PkgPath] == nil {
103                depsByPkgPath[pkg.PkgPath] = pkg
104                for path := range pkg.Imports {
105                    visit(pkg.Imports[path])
106                }
107            }
108        }
109        visit(ppkg)
110    }
111
112    // importer state
113    var (
114        insert    func(p *types.Packagename string)
115        importMap = make(map[string]*types.Package// keys are PackagePaths
116    )
117    loadFromExportData := func(imp *packages.Package) (*types.Packageerror) {
118        data := []byte(imp.ExportFile)
119        return gcimporter.IImportShallow(fsetimportMapdataimp.PkgPathinsert)
120    }
121    insert = func(p *types.Packagename string) {
122        impok := depsByPkgPath[p.Path()]
123        if !ok {
124            t.Fatalf("can't find dependency: %q"p.Path())
125        }
126        importederr := loadFromExportData(imp)
127        if err != nil {
128            t.Fatalf("unmarshal: %v"err)
129        }
130        if imported != p {
131            t.Fatalf("internal error: inconsistent packages")
132        }
133        if obj := imported.Scope().Lookup(name); obj == nil {
134            t.Fatalf("lookup %q.%s failed"imported.Path(), name)
135        }
136    }
137
138    cfg := &types.Config{
139        Error: func(e error) {
140            t.Error(e)
141        },
142        ImporterimporterFunc(func(importPath string) (*types.Packageerror) {
143            if importPath == "unsafe" {
144                return types.Unsafenil // unsafe has no exportdata
145            }
146            impok := ppkg.Imports[importPath]
147            if !ok {
148                return nilfmt.Errorf("missing import %q"importPath)
149            }
150            return loadFromExportData(imp)
151        }),
152    }
153
154    // Type-check the syntax trees.
155    tpkg_ := cfg.Check(ppkg.PkgPathfsetsyntaxnil)
156
157    // Save the export data.
158    dataerr := gcimporter.IExportShallow(fsettpkg)
159    if err != nil {
160        t.Fatalf("internal error marshalling export data: %v"err)
161    }
162    ppkg.ExportFile = string(data)
163}
164
MembersX
typecheck.RangeStmt_1997.BlockStmt.i
typecheck.RangeStmt_1997.BlockStmt.BlockStmt.f
typecheck._
TestShallowStd
TestShallowStd.t
typecheck.RangeStmt_1997.i
typecheck.BlockStmt.BlockStmt.BlockStmt.RangeStmt_2752.path
typecheck.BlockStmt.obj
typecheck.ppkg
typecheck.RangeStmt_1997.BlockStmt.filename
typecheck.depsByPkgPath
typecheck.BlockStmt.data
errgroup
typecheck.t
typecheck.fset
typecheck.group
typecheck.RangeStmt_1997.filename
typecheck.tpkg
TestShallowStd.cfg
TestShallowStd.RangeStmt_1516.root
typecheck
packages
TestShallowStd.pkgs
typecheck.err
typecheck.BlockStmt.imported
typecheck.BlockStmt.err
typecheck.cfg
TestShallowStd.err
TestShallowStd.done
TestShallowStd.BlockStmt.BlockStmt.RangeStmt_1403.imp
typecheck.syntax
typecheck.RangeStmt_1997.BlockStmt.BlockStmt.err
typecheck.data
Members
X