| // Copyright 2019 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package cache | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"go/ast" | 
 | 	"go/scanner" | 
 | 	"go/token" | 
 | 	"go/types" | 
 | 	"slices" | 
 | 	"sync" | 
 |  | 
 | 	"golang.org/x/tools/gopls/internal/cache/metadata" | 
 | 	"golang.org/x/tools/gopls/internal/cache/methodsets" | 
 | 	"golang.org/x/tools/gopls/internal/cache/parsego" | 
 | 	"golang.org/x/tools/gopls/internal/cache/testfuncs" | 
 | 	"golang.org/x/tools/gopls/internal/cache/xrefs" | 
 | 	"golang.org/x/tools/gopls/internal/protocol" | 
 | 	"golang.org/x/tools/gopls/internal/util/safetoken" | 
 | ) | 
 |  | 
 | // Convenient aliases for very heavily used types. | 
 | type ( | 
 | 	PackageID   = metadata.PackageID | 
 | 	PackagePath = metadata.PackagePath | 
 | 	PackageName = metadata.PackageName | 
 | 	ImportPath  = metadata.ImportPath | 
 | ) | 
 |  | 
 | // A Package is the union of package metadata and type checking results. | 
 | // | 
 | // TODO(rfindley): for now, we do not persist the post-processing of | 
 | // loadDiagnostics, because the value of the snapshot.packages map is just the | 
 | // package handle. Fix this. | 
 | type Package struct { | 
 | 	metadata        *metadata.Package | 
 | 	loadDiagnostics []*Diagnostic | 
 | 	pkg             *syntaxPackage | 
 | } | 
 |  | 
 | // syntaxPackage contains parse trees and type information for a package. | 
 | type syntaxPackage struct { | 
 | 	// -- identifiers -- | 
 | 	id PackageID | 
 |  | 
 | 	// -- outputs -- | 
 | 	fset            *token.FileSet // for now, same as the snapshot's FileSet | 
 | 	goFiles         []*parsego.File | 
 | 	compiledGoFiles []*parsego.File | 
 | 	diagnostics     []*Diagnostic | 
 | 	parseErrors     []scanner.ErrorList | 
 | 	typeErrors      []types.Error | 
 | 	types           *types.Package | 
 | 	typesInfo       *types.Info | 
 | 	typesSizes      types.Sizes | 
 | 	importMap       map[PackagePath]*types.Package | 
 |  | 
 | 	xrefsOnce sync.Once | 
 | 	_xrefs    []byte // only used by the xrefs method | 
 |  | 
 | 	methodsetsOnce sync.Once | 
 | 	_methodsets    *methodsets.Index // only used by the methodsets method | 
 |  | 
 | 	testsOnce sync.Once | 
 | 	_tests    *testfuncs.Index // only used by the tests method | 
 | } | 
 |  | 
 | func (p *syntaxPackage) xrefs() []byte { | 
 | 	p.xrefsOnce.Do(func() { | 
 | 		p._xrefs = xrefs.Index(p.compiledGoFiles, p.types, p.typesInfo) | 
 | 	}) | 
 | 	return p._xrefs | 
 | } | 
 |  | 
 | func (p *syntaxPackage) methodsets() *methodsets.Index { | 
 | 	p.methodsetsOnce.Do(func() { | 
 | 		p._methodsets = methodsets.NewIndex(p.fset, p.types) | 
 | 	}) | 
 | 	return p._methodsets | 
 | } | 
 |  | 
 | func (p *syntaxPackage) tests() *testfuncs.Index { | 
 | 	p.testsOnce.Do(func() { | 
 | 		p._tests = testfuncs.NewIndex(p.compiledGoFiles, p.typesInfo) | 
 | 	}) | 
 | 	return p._tests | 
 | } | 
 |  | 
 | // hasFixedFiles reports whether there are any 'fixed' compiled go files in the | 
 | // package. | 
 | // | 
 | // Intended to be used to refine bug reports. | 
 | func (p *syntaxPackage) hasFixedFiles() bool { | 
 | 	return slices.ContainsFunc(p.compiledGoFiles, (*parsego.File).Fixed) | 
 | } | 
 |  | 
 | func (p *Package) String() string { return string(p.metadata.ID) } | 
 |  | 
 | func (p *Package) Metadata() *metadata.Package { return p.metadata } | 
 |  | 
 | // A loadScope defines a package loading scope for use with go/packages. | 
 | // | 
 | // TODO(rfindley): move this to load.go. | 
 | type loadScope interface { | 
 | 	aScope() | 
 | } | 
 |  | 
 | // TODO(rfindley): move to load.go | 
 | type ( | 
 | 	fileLoadScope    protocol.DocumentURI // load packages containing a file (including command-line-arguments) | 
 | 	packageLoadScope string               // load a specific package (the value is its PackageID) | 
 | 	moduleLoadScope  struct { | 
 | 		dir        string // dir containing the go.mod file | 
 | 		modulePath string // parsed module path | 
 | 	} | 
 | 	viewLoadScope struct{} // load the workspace | 
 | ) | 
 |  | 
 | // Implement the loadScope interface. | 
 | func (fileLoadScope) aScope()    {} | 
 | func (packageLoadScope) aScope() {} | 
 | func (moduleLoadScope) aScope()  {} | 
 | func (viewLoadScope) aScope()    {} | 
 |  | 
 | func (p *Package) CompiledGoFiles() []*parsego.File { | 
 | 	return p.pkg.compiledGoFiles | 
 | } | 
 |  | 
 | func (p *Package) File(uri protocol.DocumentURI) (*parsego.File, error) { | 
 | 	return p.pkg.File(uri) | 
 | } | 
 |  | 
 | // FileEnclosing returns the file of pkg that encloses the specified position, | 
 | // which must be mapped by p.FileSet(). | 
 | func (p *Package) FileEnclosing(pos token.Pos) (*parsego.File, error) { | 
 | 	for _, files := range [...][]*parsego.File{p.pkg.compiledGoFiles, p.pkg.goFiles} { | 
 | 		for _, pgf := range files { | 
 | 			if pgf.File.FileStart <= pos && pos <= pgf.File.FileEnd { | 
 | 				return pgf, nil | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return nil, fmt.Errorf("no parsed file for position %d (%s) in %v", | 
 | 		pos, safetoken.StartPosition(p.FileSet(), pos), p.pkg.id) | 
 | } | 
 |  | 
 | func (pkg *syntaxPackage) File(uri protocol.DocumentURI) (*parsego.File, error) { | 
 | 	for _, files := range [...][]*parsego.File{pkg.compiledGoFiles, pkg.goFiles} { | 
 | 		for _, pgf := range files { | 
 | 			if pgf.URI == uri { | 
 | 				return pgf, nil | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return nil, fmt.Errorf("no parsed file for %s in %v", uri, pkg.id) | 
 | } | 
 |  | 
 | // Syntax returns parsed compiled Go files contained in this package. | 
 | func (p *Package) Syntax() []*ast.File { | 
 | 	var syntax []*ast.File | 
 | 	for _, pgf := range p.pkg.compiledGoFiles { | 
 | 		syntax = append(syntax, pgf.File) | 
 | 	} | 
 | 	return syntax | 
 | } | 
 |  | 
 | // FileSet returns the FileSet describing this package's positions. | 
 | // | 
 | // The returned FileSet is guaranteed to describe all Syntax, but may also | 
 | // describe additional files. | 
 | func (p *Package) FileSet() *token.FileSet { | 
 | 	return p.pkg.fset | 
 | } | 
 |  | 
 | // Types returns the type checked go/types.Package. | 
 | func (p *Package) Types() *types.Package { | 
 | 	return p.pkg.types | 
 | } | 
 |  | 
 | // TypesInfo returns the go/types.Info annotating the Syntax of this package | 
 | // with type information. | 
 | // | 
 | // All fields in the resulting Info are populated. | 
 | func (p *Package) TypesInfo() *types.Info { | 
 | 	return p.pkg.typesInfo | 
 | } | 
 |  | 
 | // TypesSizes returns the sizing function used for types in this package. | 
 | func (p *Package) TypesSizes() types.Sizes { | 
 | 	return p.pkg.typesSizes | 
 | } | 
 |  | 
 | // DependencyTypes returns the type checker's symbol for the specified | 
 | // package. It returns nil if path is not among the transitive | 
 | // dependencies of p, or if no symbols from that package were | 
 | // referenced during the type-checking of p. | 
 | func (p *Package) DependencyTypes(path PackagePath) *types.Package { | 
 | 	return p.pkg.importMap[path] | 
 | } | 
 |  | 
 | // ParseErrors returns a slice containing all non-empty parse errors produces | 
 | // while parsing p.Syntax, or nil if the package contains no parse errors. | 
 | func (p *Package) ParseErrors() []scanner.ErrorList { | 
 | 	return p.pkg.parseErrors | 
 | } | 
 |  | 
 | // TypeErrors returns the go/types.Errors produced during type checking this | 
 | // package, if any. | 
 | func (p *Package) TypeErrors() []types.Error { | 
 | 	return p.pkg.typeErrors | 
 | } |