1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// 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"
"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/xrefs"
"golang.org/x/tools/gopls/internal/protocol"
)
// 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
}
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 *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)
}
func (pkg *syntaxPackage) File(uri protocol.DocumentURI) (*parsego.File, error) {
for _, cgf := range pkg.compiledGoFiles {
if cgf.URI == uri {
return cgf, nil
}
}
for _, gf := range pkg.goFiles {
if gf.URI == uri {
return gf, 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
}
|