1 // Copyright 2019 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.
18 "golang.org/x/mod/module"
19 "golang.org/x/tools/go/packages"
20 "golang.org/x/tools/internal/event"
21 "golang.org/x/tools/internal/lsp/debug/tag"
22 "golang.org/x/tools/internal/lsp/source"
23 "golang.org/x/tools/internal/memoize"
24 "golang.org/x/tools/internal/span"
25 "golang.org/x/tools/internal/typesinternal"
26 errors "golang.org/x/xerrors"
29 type packageHandleKey string
31 type packageHandle struct {
32 handle *memoize.Handle
34 goFiles, compiledGoFiles []*parseGoHandle
36 // mode is the mode the files were parsed in.
39 // m is the metadata associated with the package.
42 // key is the hashed key for the package.
46 func (ph *packageHandle) packageKey() packageKey {
53 // packageData contains the data produced by type-checking a package.
54 type packageData struct {
59 // buildPackageHandle returns a packageHandle for a given package and mode.
60 func (s *snapshot) buildPackageHandle(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, error) {
61 if ph := s.getPackage(id, mode); ph != nil {
65 // Build the packageHandle for this ID and its dependencies.
66 ph, deps, err := s.buildKey(ctx, id, mode)
71 // Do not close over the packageHandle or the snapshot in the Bind function.
72 // This creates a cycle, which causes the finalizers to never run on the handles.
73 // The possible cycles are:
75 // packageHandle.h.function -> packageHandle
76 // packageHandle.h.function -> snapshot -> packageHandle
82 h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
83 snapshot := arg.(*snapshot)
85 // Begin loading the direct dependencies, in parallel.
87 for _, dep := range deps {
89 go func(dep *packageHandle) {
90 dep.check(ctx, snapshot)
95 data := &packageData{}
96 data.pkg, data.err = typeCheck(ctx, snapshot, m, mode, deps)
97 // Make sure that the workers above have finished before we return,
98 // especially in case of cancellation.
105 // Cache the handle in the snapshot. If a package handle has already
106 // been cached, addPackage will return the cached value. This is fine,
107 // since the original package handle above will have no references and be
108 // garbage collected.
109 ph = s.addPackageHandle(ph)
114 // buildKey computes the key for a given packageHandle.
115 func (s *snapshot) buildKey(ctx context.Context, id packageID, mode source.ParseMode) (*packageHandle, map[packagePath]*packageHandle, error) {
116 m := s.getMetadata(id)
118 return nil, nil, errors.Errorf("no metadata for %s", id)
120 goFiles, err := s.parseGoHandles(ctx, m.goFiles, mode)
124 compiledGoFiles, err := s.parseGoHandles(ctx, m.compiledGoFiles, mode)
128 ph := &packageHandle{
131 compiledGoFiles: compiledGoFiles,
134 // Make sure all of the depList are sorted.
135 depList := append([]packageID{}, m.deps...)
136 sort.Slice(depList, func(i, j int) bool {
137 return depList[i] < depList[j]
140 deps := make(map[packagePath]*packageHandle)
142 // Begin computing the key by getting the depKeys for all dependencies.
143 var depKeys []packageHandleKey
144 for _, depID := range depList {
145 depHandle, err := s.buildPackageHandle(ctx, depID, s.workspaceParseMode(depID))
147 event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", id, depID), err, tag.Snapshot.Of(s.id))
148 if ctx.Err() != nil {
149 return nil, nil, ctx.Err()
151 // One bad dependency should not prevent us from checking the entire package.
152 // Add a special key to mark a bad dependency.
153 depKeys = append(depKeys, packageHandleKey(fmt.Sprintf("%s import not found", id)))
156 deps[depHandle.m.pkgPath] = depHandle
157 depKeys = append(depKeys, depHandle.key)
159 experimentalKey := s.View().Options().ExperimentalPackageCacheKey
160 ph.key = checkPackageKey(ctx, ph.m.id, compiledGoFiles, m.config, depKeys, mode, experimentalKey)
164 func (s *snapshot) workspaceParseMode(id packageID) source.ParseMode {
165 if _, ws := s.isWorkspacePackage(id); ws {
166 return source.ParseFull
168 return source.ParseExported
172 func checkPackageKey(ctx context.Context, id packageID, pghs []*parseGoHandle, cfg *packages.Config, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
173 b := bytes.NewBuffer(nil)
174 b.WriteString(string(id))
175 if !experimentalKey {
176 // cfg was used to produce the other hashed inputs (package ID, parsed Go
177 // files, and deps). It should not otherwise affect the inputs to the type
178 // checker, so this experiment omits it. This should increase cache hits on
179 // the daemon as cfg contains the environment and working directory.
180 b.WriteString(hashConfig(cfg))
182 b.WriteByte(byte(mode))
183 for _, dep := range deps {
184 b.WriteString(string(dep))
186 for _, cgf := range pghs {
187 b.WriteString(cgf.file.FileIdentity().String())
189 return packageHandleKey(hashContents(b.Bytes()))
192 // hashEnv returns a hash of the snapshot's configuration.
193 func hashEnv(s *snapshot) string {
194 s.view.optionsMu.Lock()
195 env := s.view.options.EnvSlice()
196 s.view.optionsMu.Unlock()
199 for _, e := range env {
202 return hashContents(b.Bytes())
205 // hashConfig returns the hash for the *packages.Config.
206 func hashConfig(config *packages.Config) string {
207 b := bytes.NewBuffer(nil)
209 // Dir, Mode, Env, BuildFlags are the parts of the config that can change.
210 b.WriteString(config.Dir)
211 b.WriteString(string(rune(config.Mode)))
213 for _, e := range config.Env {
216 for _, f := range config.BuildFlags {
219 return hashContents(b.Bytes())
222 func (ph *packageHandle) Check(ctx context.Context, s source.Snapshot) (source.Package, error) {
223 return ph.check(ctx, s.(*snapshot))
226 func (ph *packageHandle) check(ctx context.Context, s *snapshot) (*pkg, error) {
227 v, err := ph.handle.Get(ctx, s.generation, s)
231 data := v.(*packageData)
232 return data.pkg, data.err
235 func (ph *packageHandle) CompiledGoFiles() []span.URI {
236 return ph.m.compiledGoFiles
239 func (ph *packageHandle) ID() string {
240 return string(ph.m.id)
243 func (ph *packageHandle) cached(g *memoize.Generation) (*pkg, error) {
244 v := ph.handle.Cached(g)
246 return nil, errors.Errorf("no cached type information for %s", ph.m.pkgPath)
248 data := v.(*packageData)
249 return data.pkg, data.err
252 func (s *snapshot) parseGoHandles(ctx context.Context, files []span.URI, mode source.ParseMode) ([]*parseGoHandle, error) {
253 pghs := make([]*parseGoHandle, 0, len(files))
254 for _, uri := range files {
255 fh, err := s.GetFile(ctx, uri)
259 pghs = append(pghs, s.parseGoHandle(ctx, fh, mode))
264 func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source.ParseMode, deps map[packagePath]*packageHandle) (*pkg, error) {
265 ctx, done := event.Start(ctx, "cache.importer.typeCheck", tag.Package.Of(string(m.id)))
268 var rawErrors []error
269 for _, err := range m.errors {
270 rawErrors = append(rawErrors, err)
273 fset := snapshot.view.session.cache.fset
277 goFiles: make([]*source.ParsedGoFile, len(m.goFiles)),
278 compiledGoFiles: make([]*source.ParsedGoFile, len(m.compiledGoFiles)),
279 imports: make(map[packagePath]*pkg),
280 typesSizes: m.typesSizes,
281 typesInfo: &types.Info{
282 Types: make(map[ast.Expr]types.TypeAndValue),
283 Defs: make(map[*ast.Ident]types.Object),
284 Uses: make(map[*ast.Ident]types.Object),
285 Implicits: make(map[ast.Node]types.Object),
286 Selections: make(map[*ast.SelectorExpr]*types.Selection),
287 Scopes: make(map[ast.Node]*types.Scope),
290 // If this is a replaced module in the workspace, the version is
291 // meaningless, and we don't want clients to access it.
293 version := m.module.Version
294 if source.IsWorkspaceModuleVersion(version) {
297 pkg.version = &module.Version{
303 files = make([]*ast.File, len(m.compiledGoFiles))
304 parseErrors = make([]error, len(m.compiledGoFiles))
305 actualErrors = make([]error, len(m.compiledGoFiles))
311 for i, cgf := range m.compiledGoFiles {
313 go func(i int, cgf span.URI) {
315 fh, err := snapshot.GetFile(ctx, cgf)
317 actualErrors[i] = err
320 pgh := snapshot.parseGoHandle(ctx, fh, mode)
321 pgf, fixed, err := snapshot.parseGo(ctx, pgh)
323 actualErrors[i] = err
326 pkg.compiledGoFiles[i] = pgf
327 files[i], parseErrors[i], actualErrors[i] = pgf.File, pgf.ParseErr, err
330 skipTypeErrors = skipTypeErrors || fixed
334 for i, gf := range m.goFiles {
336 // We need to parse the non-compiled go files, but we don't care about their errors.
337 go func(i int, gf span.URI) {
339 fh, err := snapshot.GetFile(ctx, gf)
343 pgf, _ := snapshot.ParseGo(ctx, fh, mode)
348 for _, err := range actualErrors {
354 for _, e := range parseErrors {
356 rawErrors = append(rawErrors, e)
361 for _, f := range files {
369 // Use the default type information for the unsafe package.
370 if pkg.m.pkgPath == "unsafe" {
371 pkg.types = types.Unsafe
372 // Don't type check Unsafe: it's unnecessary, and doing so exposes a data
373 // race to Unsafe.completed.
375 } else if len(files) == 0 { // not the unsafe package, no parsed files
376 // Try to attach errors messages to the file as much as possible.
378 for _, e := range rawErrors {
379 srcErr, err := sourceError(ctx, snapshot, pkg, e)
384 pkg.errors = append(pkg.errors, srcErr)
389 return nil, errors.Errorf("no parsed files for package %s, expected: %v, list errors: %v", pkg.m.pkgPath, pkg.compiledGoFiles, rawErrors)
391 pkg.types = types.NewPackage(string(m.pkgPath), string(m.name))
394 cfg := &types.Config{
395 Error: func(e error) {
396 // If we have fixed parse errors in any of the files,
397 // we should hide type errors, as they may be completely nonsensical.
401 rawErrors = append(rawErrors, e)
403 Importer: importerFunc(func(pkgPath string) (*types.Package, error) {
404 // If the context was cancelled, we should abort.
405 if ctx.Err() != nil {
406 return nil, ctx.Err()
408 dep := resolveImportPath(pkgPath, pkg, deps)
410 return nil, errors.Errorf("no package for import %s", pkgPath)
412 if !isValidImport(m.pkgPath, dep.m.pkgPath) {
413 return nil, errors.Errorf("invalid use of internal package %s", pkgPath)
415 depPkg, err := dep.check(ctx, snapshot)
419 pkg.imports[depPkg.m.pkgPath] = depPkg
420 return depPkg.types, nil
423 // We want to type check cgo code if go/types supports it.
424 // We passed typecheckCgo to go/packages when we Loaded.
425 typesinternal.SetUsesCgo(cfg)
427 check := types.NewChecker(cfg, fset, pkg.types, pkg.typesInfo)
429 // Type checking errors are handled via the config, so ignore them here.
430 _ = check.Files(files)
431 // If the context was cancelled, we may have returned a ton of transient
432 // errors to the type checker. Swallow them.
433 if ctx.Err() != nil {
434 return nil, ctx.Err()
437 // We don't care about a package's errors unless we have parsed it in full.
438 if mode == source.ParseFull {
439 expandErrors(rawErrors)
440 for _, e := range rawErrors {
441 srcErr, err := sourceError(ctx, snapshot, pkg, e)
443 event.Error(ctx, "unable to compute error positions", err, tag.Package.Of(pkg.ID()))
446 pkg.errors = append(pkg.errors, srcErr)
447 if err, ok := e.(extendedError); ok {
448 pkg.typeErrors = append(pkg.typeErrors, err.primary)
456 type extendedError struct {
458 secondaries []types.Error
461 func (e extendedError) Error() string {
462 return e.primary.Error()
465 // expandErrors duplicates "secondary" errors by mapping them to their main
466 // error. Some errors returned by the type checker are followed by secondary
467 // errors which give more information about the error. These are errors in
468 // their own right, and they are marked by starting with \t. For instance, when
469 // there is a multiply-defined function, the secondary error points back to the
470 // definition first noticed.
472 // This code associates the secondary error with its primary error, which can
473 // then be used as RelatedInformation when the error becomes a diagnostic.
474 func expandErrors(errs []error) []error {
475 for i := 0; i < len(errs); {
476 e, ok := errs[i].(types.Error)
481 enew := extendedError{
485 for ; j < len(errs); j++ {
486 spl, ok := errs[j].(types.Error)
487 if !ok || len(spl.Msg) == 0 || spl.Msg[0] != '\t' {
490 enew.secondaries = append(enew.secondaries, spl)
498 // resolveImportPath resolves an import path in pkg to a package from deps.
499 // It should produce the same results as resolveImportPath:
500 // https://cs.opensource.google/go/go/+/master:src/cmd/go/internal/load/pkg.go;drc=641918ee09cb44d282a30ee8b66f99a0b63eaef9;l=990.
501 func resolveImportPath(importPath string, pkg *pkg, deps map[packagePath]*packageHandle) *packageHandle {
502 if dep := deps[packagePath(importPath)]; dep != nil {
505 // We may be in GOPATH mode, in which case we need to check vendor dirs.
506 searchDir := path.Dir(pkg.PkgPath())
508 vdir := packagePath(path.Join(searchDir, "vendor", importPath))
509 if vdep := deps[vdir]; vdep != nil {
513 // Search until Dir doesn't take us anywhere new, e.g. "." or "/".
514 next := path.Dir(searchDir)
515 if searchDir == next {
521 // Vendor didn't work. Let's try minimal module compatibility mode.
522 // In MMC, the packagePath is the canonical (.../vN/...) path, which
523 // is hard to calculate. But the go command has already resolved the ID
524 // to the non-versioned path, and we can take advantage of that.
525 for _, dep := range deps {
526 if dep.ID() == importPath {
533 func isValidImport(pkgPath, importPkgPath packagePath) bool {
534 i := strings.LastIndex(string(importPkgPath), "/internal/")
538 if pkgPath == "command-line-arguments" {
541 return strings.HasPrefix(string(pkgPath), string(importPkgPath[:i]))
544 // An importFunc is an implementation of the single-method
545 // types.Importer interface based on a function value.
546 type importerFunc func(path string) (*types.Package, error)
548 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }