golang.org/x/tools/gopls@v0.15.3/internal/golang/snapshot.go (about) 1 // Copyright 2018 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 golang 6 7 import ( 8 "context" 9 "fmt" 10 11 "golang.org/x/tools/gopls/internal/cache" 12 "golang.org/x/tools/gopls/internal/cache/metadata" 13 "golang.org/x/tools/gopls/internal/cache/parsego" 14 "golang.org/x/tools/gopls/internal/protocol" 15 ) 16 17 // NarrowestMetadataForFile returns metadata for the narrowest package 18 // (the one with the fewest files) that encloses the specified file. 19 // The result may be a test variant, but never an intermediate test variant. 20 func NarrowestMetadataForFile(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI) (*metadata.Package, error) { 21 mps, err := snapshot.MetadataForFile(ctx, uri) 22 if err != nil { 23 return nil, err 24 } 25 metadata.RemoveIntermediateTestVariants(&mps) 26 if len(mps) == 0 { 27 return nil, fmt.Errorf("no package metadata for file %s", uri) 28 } 29 return mps[0], nil 30 } 31 32 // NarrowestPackageForFile is a convenience function that selects the narrowest 33 // non-ITV package to which this file belongs, type-checks it in the requested 34 // mode (full or workspace), and returns it, along with the parse tree of that 35 // file. 36 // 37 // The "narrowest" package is the one with the fewest number of files that 38 // includes the given file. This solves the problem of test variants, as the 39 // test will have more files than the non-test package. 40 // 41 // An intermediate test variant (ITV) package has identical source to a regular 42 // package but resolves imports differently. gopls should never need to 43 // type-check them. 44 // 45 // Type-checking is expensive. Call snapshot.ParseGo if all you need is a parse 46 // tree, or snapshot.MetadataForFile if you only need metadata. 47 func NarrowestPackageForFile(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI) (*cache.Package, *ParsedGoFile, error) { 48 return selectPackageForFile(ctx, snapshot, uri, func(metas []*metadata.Package) *metadata.Package { return metas[0] }) 49 } 50 51 // WidestPackageForFile is a convenience function that selects the widest 52 // non-ITV package to which this file belongs, type-checks it in the requested 53 // mode (full or workspace), and returns it, along with the parse tree of that 54 // file. 55 // 56 // The "widest" package is the one with the most number of files that includes 57 // the given file. Which is the test variant if one exists. 58 // 59 // An intermediate test variant (ITV) package has identical source to a regular 60 // package but resolves imports differently. gopls should never need to 61 // type-check them. 62 // 63 // Type-checking is expensive. Call snapshot.ParseGo if all you need is a parse 64 // tree, or snapshot.MetadataForFile if you only need metadata. 65 func WidestPackageForFile(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI) (*cache.Package, *ParsedGoFile, error) { 66 return selectPackageForFile(ctx, snapshot, uri, func(metas []*metadata.Package) *metadata.Package { return metas[len(metas)-1] }) 67 } 68 69 func selectPackageForFile(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI, selector func([]*metadata.Package) *metadata.Package) (*cache.Package, *ParsedGoFile, error) { 70 mps, err := snapshot.MetadataForFile(ctx, uri) 71 if err != nil { 72 return nil, nil, err 73 } 74 metadata.RemoveIntermediateTestVariants(&mps) 75 if len(mps) == 0 { 76 return nil, nil, fmt.Errorf("no package metadata for file %s", uri) 77 } 78 mp := selector(mps) 79 pkgs, err := snapshot.TypeCheck(ctx, mp.ID) 80 if err != nil { 81 return nil, nil, err 82 } 83 pkg := pkgs[0] 84 pgf, err := pkg.File(uri) 85 if err != nil { 86 return nil, nil, err // "can't happen" 87 } 88 return pkg, pgf, err 89 } 90 91 type ParsedGoFile = parsego.File 92 93 const ( 94 ParseHeader = parsego.ParseHeader 95 ParseFull = parsego.ParseFull 96 ) 97 98 type ( 99 PackageID = metadata.PackageID 100 PackagePath = metadata.PackagePath 101 PackageName = metadata.PackageName 102 ImportPath = metadata.ImportPath 103 ) 104 105 type unit = struct{}