internal/lsp: reduce the api surface of the cache package
The cache now exposes only one symbol, NewView This is preparing the cache for a re-write Change-Id: I411c2cd7a7edc2e7c774218c6786f9fd4fcc53cb Reviewed-on: https://go-review.googlesource.com/c/tools/+/176924 Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
707862fa78
commit
ce09bef8aa
|
@ -17,7 +17,7 @@ import (
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) parse(ctx context.Context, f *File) ([]packages.Error, error) {
|
func (v *view) parse(ctx context.Context, f *file) ([]packages.Error, error) {
|
||||||
v.mcache.mu.Lock()
|
v.mcache.mu.Lock()
|
||||||
defer v.mcache.mu.Unlock()
|
defer v.mcache.mu.Unlock()
|
||||||
|
|
||||||
|
@ -61,9 +61,9 @@ func (v *View) parse(ctx context.Context, f *File) ([]packages.Error, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) checkMetadata(ctx context.Context, f *File) ([]packages.Error, error) {
|
func (v *view) checkMetadata(ctx context.Context, f *file) ([]packages.Error, error) {
|
||||||
if v.reparseImports(ctx, f, f.filename) {
|
if v.reparseImports(ctx, f, f.filename) {
|
||||||
cfg := v.Config
|
cfg := v.config
|
||||||
cfg.Mode = packages.LoadImports | packages.NeedTypesSizes
|
cfg.Mode = packages.LoadImports | packages.NeedTypesSizes
|
||||||
pkgs, err := packages.Load(&cfg, fmt.Sprintf("file=%s", f.filename))
|
pkgs, err := packages.Load(&cfg, fmt.Sprintf("file=%s", f.filename))
|
||||||
if len(pkgs) == 0 {
|
if len(pkgs) == 0 {
|
||||||
|
@ -92,13 +92,13 @@ func (v *View) checkMetadata(ctx context.Context, f *File) ([]packages.Error, er
|
||||||
|
|
||||||
// reparseImports reparses a file's import declarations to determine if they
|
// reparseImports reparses a file's import declarations to determine if they
|
||||||
// have changed.
|
// have changed.
|
||||||
func (v *View) reparseImports(ctx context.Context, f *File, filename string) bool {
|
func (v *view) reparseImports(ctx context.Context, f *file, filename string) bool {
|
||||||
if f.meta == nil {
|
if f.meta == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Get file content in case we don't already have it?
|
// Get file content in case we don't already have it?
|
||||||
f.read(ctx)
|
f.read(ctx)
|
||||||
parsed, _ := parser.ParseFile(v.Config.Fset, filename, f.content, parser.ImportsOnly)
|
parsed, _ := parser.ParseFile(v.config.Fset, filename, f.content, parser.ImportsOnly)
|
||||||
if parsed == nil {
|
if parsed == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ func (v *View) reparseImports(ctx context.Context, f *File, filename string) boo
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
|
func (v *view) link(pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
|
||||||
m, ok := v.mcache.packages[pkgPath]
|
m, ok := v.mcache.packages[pkgPath]
|
||||||
if !ok {
|
if !ok {
|
||||||
m = &metadata{
|
m = &metadata{
|
||||||
|
@ -156,7 +156,7 @@ func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *me
|
||||||
}
|
}
|
||||||
|
|
||||||
type importer struct {
|
type importer struct {
|
||||||
view *View
|
view *view
|
||||||
|
|
||||||
// seen maintains the set of previously imported packages.
|
// seen maintains the set of previously imported packages.
|
||||||
// If we have seen a package that is already in this map, we have a circular import.
|
// If we have seen a package that is already in this map, we have a circular import.
|
||||||
|
@ -193,7 +193,7 @@ func (imp *importer) Import(pkgPath string) (*types.Package, error) {
|
||||||
return e.pkg.types, nil
|
return e.pkg.types, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
|
func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
|
||||||
meta, ok := imp.view.mcache.packages[pkgPath]
|
meta, ok := imp.view.mcache.packages[pkgPath]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no metadata for %v", pkgPath)
|
return nil, fmt.Errorf("no metadata for %v", pkgPath)
|
||||||
|
@ -205,11 +205,11 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
|
||||||
} else {
|
} else {
|
||||||
typ = types.NewPackage(meta.pkgPath, meta.name)
|
typ = types.NewPackage(meta.pkgPath, meta.name)
|
||||||
}
|
}
|
||||||
pkg := &Package{
|
pkg := &pkg{
|
||||||
id: meta.id,
|
id: meta.id,
|
||||||
pkgPath: meta.pkgPath,
|
pkgPath: meta.pkgPath,
|
||||||
files: meta.files,
|
files: meta.files,
|
||||||
imports: make(map[string]*Package),
|
imports: make(map[string]*pkg),
|
||||||
types: typ,
|
types: typ,
|
||||||
typesSizes: meta.typesSizes,
|
typesSizes: meta.typesSizes,
|
||||||
typesInfo: &types.Info{
|
typesInfo: &types.Info{
|
||||||
|
@ -246,7 +246,7 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
|
||||||
ctx: imp.ctx,
|
ctx: imp.ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
check := types.NewChecker(cfg, imp.view.Config.Fset, pkg.types, pkg.typesInfo)
|
check := types.NewChecker(cfg, imp.view.config.Fset, pkg.types, pkg.typesInfo)
|
||||||
check.Files(pkg.syntax)
|
check.Files(pkg.syntax)
|
||||||
|
|
||||||
// Add every file in this package to our cache.
|
// Add every file in this package to our cache.
|
||||||
|
@ -255,14 +255,14 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) cachePackage(ctx context.Context, pkg *Package, meta *metadata) {
|
func (v *view) cachePackage(ctx context.Context, pkg *pkg, meta *metadata) {
|
||||||
for _, file := range pkg.GetSyntax() {
|
for _, file := range pkg.GetSyntax() {
|
||||||
// TODO: If a file is in multiple packages, which package do we store?
|
// TODO: If a file is in multiple packages, which package do we store?
|
||||||
if !file.Pos().IsValid() {
|
if !file.Pos().IsValid() {
|
||||||
v.Logger().Errorf(ctx, "invalid position for file %v", file.Name)
|
v.Logger().Errorf(ctx, "invalid position for file %v", file.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tok := v.Config.Fset.File(file.Pos())
|
tok := v.config.Fset.File(file.Pos())
|
||||||
if tok == nil {
|
if tok == nil {
|
||||||
v.Logger().Errorf(ctx, "no token.File for %v", file.Name)
|
v.Logger().Errorf(ctx, "no token.File for %v", file.Name)
|
||||||
continue
|
continue
|
||||||
|
@ -302,7 +302,7 @@ func (v *View) cachePackage(ctx context.Context, pkg *Package, meta *metadata) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) appendPkgError(pkg *Package, err error) {
|
func (v *view) appendPkgError(pkg *pkg, err error) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ func (v *View) appendPkgError(pkg *Package, err error) {
|
||||||
}
|
}
|
||||||
case types.Error:
|
case types.Error:
|
||||||
errs = append(errs, packages.Error{
|
errs = append(errs, packages.Error{
|
||||||
Pos: v.Config.Fset.Position(err.Pos).String(),
|
Pos: v.config.Fset.Position(err.Pos).String(),
|
||||||
Msg: err.Msg,
|
Msg: err.Msg,
|
||||||
Kind: packages.TypeError,
|
Kind: packages.TypeError,
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,18 +16,18 @@ import (
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
// File holds all the information we know about a file.
|
// file holds all the information we know about a file.
|
||||||
type File struct {
|
type file struct {
|
||||||
uris []span.URI
|
uris []span.URI
|
||||||
filename string
|
filename string
|
||||||
basename string
|
basename string
|
||||||
|
|
||||||
view *View
|
view *view
|
||||||
active bool
|
active bool
|
||||||
content []byte
|
content []byte
|
||||||
ast *ast.File
|
ast *ast.File
|
||||||
token *token.File
|
token *token.File
|
||||||
pkg *Package
|
pkg *pkg
|
||||||
meta *metadata
|
meta *metadata
|
||||||
imports []*ast.ImportSpec
|
imports []*ast.ImportSpec
|
||||||
}
|
}
|
||||||
|
@ -36,17 +36,17 @@ func basename(filename string) string {
|
||||||
return strings.ToLower(filepath.Base(filename))
|
return strings.ToLower(filepath.Base(filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) URI() span.URI {
|
func (f *file) URI() span.URI {
|
||||||
return f.uris[0]
|
return f.uris[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// View returns the view associated with the file.
|
// View returns the view associated with the file.
|
||||||
func (f *File) View() source.View {
|
func (f *file) View() source.View {
|
||||||
return f.view
|
return f.view
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContent returns the contents of the file, reading it from file system if needed.
|
// GetContent returns the contents of the file, reading it from file system if needed.
|
||||||
func (f *File) GetContent(ctx context.Context) []byte {
|
func (f *file) GetContent(ctx context.Context) []byte {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@ func (f *File) GetContent(ctx context.Context) []byte {
|
||||||
return f.content
|
return f.content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) GetFileSet(ctx context.Context) *token.FileSet {
|
func (f *file) GetFileSet(ctx context.Context) *token.FileSet {
|
||||||
return f.view.Config.Fset
|
return f.view.config.Fset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) GetToken(ctx context.Context) *token.File {
|
func (f *file) GetToken(ctx context.Context) *token.File {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ func (f *File) GetToken(ctx context.Context) *token.File {
|
||||||
return f.token
|
return f.token
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) GetAST(ctx context.Context) *ast.File {
|
func (f *file) GetAST(ctx context.Context) *ast.File {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ func (f *File) GetAST(ctx context.Context) *ast.File {
|
||||||
return f.ast
|
return f.ast
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) GetPackage(ctx context.Context) source.Package {
|
func (f *file) GetPackage(ctx context.Context) source.Package {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func (f *File) GetPackage(ctx context.Context) source.Package {
|
||||||
if errs, err := f.view.parse(ctx, f); err != nil {
|
if errs, err := f.view.parse(ctx, f); err != nil {
|
||||||
// Create diagnostics for errors if we are able to.
|
// Create diagnostics for errors if we are able to.
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return &Package{errors: errs}
|
return &pkg{errors: errs}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func (f *File) GetPackage(ctx context.Context) source.Package {
|
||||||
|
|
||||||
// read is the internal part of GetContent. It assumes that the caller is
|
// read is the internal part of GetContent. It assumes that the caller is
|
||||||
// holding the mutex of the file's view.
|
// holding the mutex of the file's view.
|
||||||
func (f *File) read(ctx context.Context) {
|
func (f *file) read(ctx context.Context) {
|
||||||
if f.content != nil {
|
if f.content != nil {
|
||||||
if len(f.view.contentChanges) == 0 {
|
if len(f.view.contentChanges) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -118,7 +118,7 @@ func (f *File) read(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We might have the content saved in an overlay.
|
// We might have the content saved in an overlay.
|
||||||
if content, ok := f.view.Config.Overlay[f.filename]; ok {
|
if content, ok := f.view.config.Overlay[f.filename]; ok {
|
||||||
f.content = content
|
f.content = content
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -132,11 +132,11 @@ func (f *File) read(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPopulated returns true if all of the computed fields of the file are set.
|
// isPopulated returns true if all of the computed fields of the file are set.
|
||||||
func (f *File) isPopulated() bool {
|
func (f *file) isPopulated() bool {
|
||||||
return f.ast != nil && f.token != nil && f.pkg != nil && f.meta != nil && f.imports != nil
|
return f.ast != nil && f.token != nil && f.pkg != nil && f.meta != nil && f.imports != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
|
func (f *file) GetActiveReverseDeps(ctx context.Context) []source.File {
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -149,7 +149,7 @@ func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
|
||||||
defer f.view.mcache.mu.Unlock()
|
defer f.view.mcache.mu.Unlock()
|
||||||
|
|
||||||
seen := make(map[string]struct{}) // visited packages
|
seen := make(map[string]struct{}) // visited packages
|
||||||
results := make(map[*File]struct{})
|
results := make(map[*file]struct{})
|
||||||
f.view.reverseDeps(ctx, seen, results, pkg.PkgPath())
|
f.view.reverseDeps(ctx, seen, results, pkg.PkgPath())
|
||||||
|
|
||||||
files := make([]source.File, 0, len(results))
|
files := make([]source.File, 0, len(results))
|
||||||
|
@ -166,7 +166,7 @@ func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) reverseDeps(ctx context.Context, seen map[string]struct{}, results map[*File]struct{}, pkgPath string) {
|
func (v *view) reverseDeps(ctx context.Context, seen map[string]struct{}, results map[*file]struct{}, pkgPath string) {
|
||||||
if _, ok := seen[pkgPath]; ok {
|
if _, ok := seen[pkgPath]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
|
||||||
parsed := make([]*ast.File, n)
|
parsed := make([]*ast.File, n)
|
||||||
errors := make([]error, n)
|
errors := make([]error, n)
|
||||||
for i, filename := range filenames {
|
for i, filename := range filenames {
|
||||||
if imp.view.Config.Context.Err() != nil {
|
if imp.view.config.Context.Err() != nil {
|
||||||
parsed[i] = nil
|
parsed[i] = nil
|
||||||
errors[i] = imp.view.Config.Context.Err()
|
errors[i] = imp.view.config.Context.Err()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
|
||||||
// We don't have a cached AST for this file.
|
// We don't have a cached AST for this file.
|
||||||
var src []byte
|
var src []byte
|
||||||
// Check for an available overlay.
|
// Check for an available overlay.
|
||||||
for f, contents := range imp.view.Config.Overlay {
|
for f, contents := range imp.view.config.Overlay {
|
||||||
if sameFile(f, filename) {
|
if sameFile(f, filename) {
|
||||||
src = contents
|
src = contents
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,11 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
|
||||||
parsed[i], errors[i] = nil, err
|
parsed[i], errors[i] = nil, err
|
||||||
} else {
|
} else {
|
||||||
// ParseFile may return both an AST and an error.
|
// ParseFile may return both an AST and an error.
|
||||||
parsed[i], errors[i] = imp.view.Config.ParseFile(imp.view.Config.Fset, filename, src)
|
parsed[i], errors[i] = imp.view.config.ParseFile(imp.view.config.Fset, filename, src)
|
||||||
|
|
||||||
// Fix any badly parsed parts of the AST.
|
// Fix any badly parsed parts of the AST.
|
||||||
if file := parsed[i]; file != nil {
|
if file := parsed[i]; file != nil {
|
||||||
tok := imp.view.Config.Fset.File(file.Pos())
|
tok := imp.view.config.Fset.File(file.Pos())
|
||||||
imp.view.fix(imp.ctx, parsed[i], tok, src)
|
imp.view.fix(imp.ctx, parsed[i], tok, src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ func sameFile(x, y string) bool {
|
||||||
// fix inspects and potentially modifies any *ast.BadStmts or *ast.BadExprs in the AST.
|
// fix inspects and potentially modifies any *ast.BadStmts or *ast.BadExprs in the AST.
|
||||||
|
|
||||||
// We attempt to modify the AST such that we can type-check it more effectively.
|
// We attempt to modify the AST such that we can type-check it more effectively.
|
||||||
func (v *View) fix(ctx context.Context, file *ast.File, tok *token.File, src []byte) {
|
func (v *view) fix(ctx context.Context, file *ast.File, tok *token.File, src []byte) {
|
||||||
var parent ast.Node
|
var parent ast.Node
|
||||||
ast.Inspect(file, func(n ast.Node) bool {
|
ast.Inspect(file, func(n ast.Node) bool {
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
@ -167,7 +167,7 @@ func (v *View) fix(ctx context.Context, file *ast.File, tok *token.File, src []b
|
||||||
// this statement entirely, and we can't use the type information when completing.
|
// this statement entirely, and we can't use the type information when completing.
|
||||||
// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST,
|
// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST,
|
||||||
// instead of the *ast.BadStmt.
|
// instead of the *ast.BadStmt.
|
||||||
func (v *View) parseDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) error {
|
func (v *view) parseDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) error {
|
||||||
// Check if we have a bad statement containing either a "go" or "defer".
|
// Check if we have a bad statement containing either a "go" or "defer".
|
||||||
s := &scanner.Scanner{}
|
s := &scanner.Scanner{}
|
||||||
s.Init(tok, src, nil, 0)
|
s.Init(tok, src, nil, 0)
|
||||||
|
@ -260,7 +260,7 @@ FindTo:
|
||||||
|
|
||||||
// offsetPositions applies an offset to the positions in an ast.Node.
|
// offsetPositions applies an offset to the positions in an ast.Node.
|
||||||
// TODO(rstambler): Add more cases here as they become necessary.
|
// TODO(rstambler): Add more cases here as they become necessary.
|
||||||
func (v *View) offsetPositions(expr ast.Expr, offset token.Pos) {
|
func (v *view) offsetPositions(expr ast.Expr, offset token.Pos) {
|
||||||
ast.Inspect(expr, func(n ast.Node) bool {
|
ast.Inspect(expr, func(n ast.Node) bool {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
|
|
|
@ -16,13 +16,13 @@ import (
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Package contains the type information needed by the source package.
|
// pkg contains the type information needed by the source package.
|
||||||
type Package struct {
|
type pkg struct {
|
||||||
id, pkgPath string
|
id, pkgPath string
|
||||||
files []string
|
files []string
|
||||||
syntax []*ast.File
|
syntax []*ast.File
|
||||||
errors []packages.Error
|
errors []packages.Error
|
||||||
imports map[string]*Package
|
imports map[string]*pkg
|
||||||
types *types.Package
|
types *types.Package
|
||||||
typesInfo *types.Info
|
typesInfo *types.Info
|
||||||
typesSizes types.Sizes
|
typesSizes types.Sizes
|
||||||
|
@ -41,7 +41,7 @@ type analysisEntry struct {
|
||||||
*source.Action
|
*source.Action
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*source.Action, error) {
|
func (pkg *pkg) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*source.Action, error) {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
@ -128,39 +128,39 @@ func (pkg *Package) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*
|
||||||
return e.Action, nil
|
return e.Action, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) PkgPath() string {
|
func (pkg *pkg) PkgPath() string {
|
||||||
return pkg.pkgPath
|
return pkg.pkgPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetFilenames() []string {
|
func (pkg *pkg) GetFilenames() []string {
|
||||||
return pkg.files
|
return pkg.files
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetSyntax() []*ast.File {
|
func (pkg *pkg) GetSyntax() []*ast.File {
|
||||||
return pkg.syntax
|
return pkg.syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetErrors() []packages.Error {
|
func (pkg *pkg) GetErrors() []packages.Error {
|
||||||
return pkg.errors
|
return pkg.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetTypes() *types.Package {
|
func (pkg *pkg) GetTypes() *types.Package {
|
||||||
return pkg.types
|
return pkg.types
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetTypesInfo() *types.Info {
|
func (pkg *pkg) GetTypesInfo() *types.Info {
|
||||||
return pkg.typesInfo
|
return pkg.typesInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetTypesSizes() types.Sizes {
|
func (pkg *pkg) GetTypesSizes() types.Sizes {
|
||||||
return pkg.typesSizes
|
return pkg.typesSizes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) IsIllTyped() bool {
|
func (pkg *pkg) IsIllTyped() bool {
|
||||||
return pkg.types == nil && pkg.typesInfo == nil
|
return pkg.types == nil && pkg.typesInfo == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkg *Package) GetImport(pkgPath string) source.Package {
|
func (pkg *pkg) GetImport(pkgPath string) source.Package {
|
||||||
imported := pkg.imports[pkgPath]
|
imported := pkg.imports[pkgPath]
|
||||||
// Be careful not to return a nil pointer because that still satisfies the
|
// Be careful not to return a nil pointer because that still satisfies the
|
||||||
// interface.
|
// interface.
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
type View struct {
|
type view struct {
|
||||||
// mu protects all mutable state of the view.
|
// mu protects all mutable state of the view.
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
|
@ -40,19 +40,19 @@ type View struct {
|
||||||
log xlog.Logger
|
log xlog.Logger
|
||||||
|
|
||||||
// Name is the user visible name of this view.
|
// Name is the user visible name of this view.
|
||||||
Name string
|
name string
|
||||||
|
|
||||||
// Folder is the root of this view.
|
// Folder is the root of this view.
|
||||||
Folder span.URI
|
folder span.URI
|
||||||
|
|
||||||
// Config is the configuration used for the view's interaction with the
|
// Config is the configuration used for the view's interaction with the
|
||||||
// go/packages API. It is shared across all views.
|
// go/packages API. It is shared across all views.
|
||||||
Config packages.Config
|
config packages.Config
|
||||||
|
|
||||||
// keep track of files by uri and by basename, a single file may be mapped
|
// keep track of files by uri and by basename, a single file may be mapped
|
||||||
// to multiple uris, and the same basename may map to multiple files
|
// to multiple uris, and the same basename may map to multiple files
|
||||||
filesByURI map[span.URI]*File
|
filesByURI map[span.URI]*file
|
||||||
filesByBase map[string][]*File
|
filesByBase map[string][]*file
|
||||||
|
|
||||||
// contentChanges saves the content changes for a given state of the view.
|
// contentChanges saves the content changes for a given state of the view.
|
||||||
// When type information is requested by the view, all of the dirty changes
|
// When type information is requested by the view, all of the dirty changes
|
||||||
|
@ -89,24 +89,24 @@ type packageCache struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type entry struct {
|
type entry struct {
|
||||||
pkg *Package
|
pkg *pkg
|
||||||
err error
|
err error
|
||||||
ready chan struct{} // closed to broadcast ready condition
|
ready chan struct{} // closed to broadcast ready condition
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI, config *packages.Config) *View {
|
func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI, config *packages.Config) source.View {
|
||||||
backgroundCtx, cancel := context.WithCancel(ctx)
|
backgroundCtx, cancel := context.WithCancel(ctx)
|
||||||
v := &View{
|
v := &view{
|
||||||
baseCtx: ctx,
|
baseCtx: ctx,
|
||||||
backgroundCtx: backgroundCtx,
|
backgroundCtx: backgroundCtx,
|
||||||
builtinPkg: builtinPkg(*config),
|
builtinPkg: builtinPkg(*config),
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
log: log,
|
log: log,
|
||||||
Config: *config,
|
config: *config,
|
||||||
Name: name,
|
name: name,
|
||||||
Folder: folder,
|
folder: folder,
|
||||||
filesByURI: make(map[span.URI]*File),
|
filesByURI: make(map[span.URI]*file),
|
||||||
filesByBase: make(map[string][]*File),
|
filesByBase: make(map[string][]*file),
|
||||||
contentChanges: make(map[span.URI]func()),
|
contentChanges: make(map[span.URI]func()),
|
||||||
mcache: &metadataCache{
|
mcache: &metadataCache{
|
||||||
packages: make(map[string]*metadata),
|
packages: make(map[string]*metadata),
|
||||||
|
@ -118,14 +118,34 @@ func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI,
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) BackgroundContext() context.Context {
|
// Name returns the user visible name of this view.
|
||||||
|
func (v *view) Name() string {
|
||||||
|
return v.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Folder returns the root of this view.
|
||||||
|
func (v *view) Folder() span.URI {
|
||||||
|
return v.folder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns the configuration used for the view's interaction with the
|
||||||
|
// go/packages API. It is shared across all views.
|
||||||
|
func (v *view) Config() packages.Config {
|
||||||
|
return v.config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *view) SetEnv(env []string) {
|
||||||
|
v.config.Env = env
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *view) BackgroundContext() context.Context {
|
||||||
v.mu.Lock()
|
v.mu.Lock()
|
||||||
defer v.mu.Unlock()
|
defer v.mu.Unlock()
|
||||||
|
|
||||||
return v.backgroundCtx
|
return v.backgroundCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) BuiltinPackage() *ast.Package {
|
func (v *view) BuiltinPackage() *ast.Package {
|
||||||
return v.builtinPkg
|
return v.builtinPkg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +171,12 @@ func builtinPkg(cfg packages.Config) *ast.Package {
|
||||||
return bpkg
|
return bpkg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) FileSet() *token.FileSet {
|
func (v *view) FileSet() *token.FileSet {
|
||||||
return v.Config.Fset
|
return v.config.Fset
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetContent sets the overlay contents for a file.
|
// SetContent sets the overlay contents for a file.
|
||||||
func (v *View) SetContent(ctx context.Context, uri span.URI, content []byte) error {
|
func (v *view) SetContent(ctx context.Context, uri span.URI, content []byte) error {
|
||||||
v.mu.Lock()
|
v.mu.Lock()
|
||||||
defer v.mu.Unlock()
|
defer v.mu.Unlock()
|
||||||
|
|
||||||
|
@ -175,7 +195,7 @@ func (v *View) SetContent(ctx context.Context, uri span.URI, content []byte) err
|
||||||
// applyContentChanges applies all of the changed content stored in the view.
|
// applyContentChanges applies all of the changed content stored in the view.
|
||||||
// It is assumed that the caller has locked both the view's and the mcache's
|
// It is assumed that the caller has locked both the view's and the mcache's
|
||||||
// mutexes.
|
// mutexes.
|
||||||
func (v *View) applyContentChanges(ctx context.Context) error {
|
func (v *view) applyContentChanges(ctx context.Context) error {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
|
@ -193,7 +213,7 @@ func (v *View) applyContentChanges(ctx context.Context) error {
|
||||||
|
|
||||||
// setContent applies a content update for a given file. It assumes that the
|
// setContent applies a content update for a given file. It assumes that the
|
||||||
// caller is holding the view's mutex.
|
// caller is holding the view's mutex.
|
||||||
func (v *View) applyContentChange(uri span.URI, content []byte) {
|
func (v *view) applyContentChange(uri span.URI, content []byte) {
|
||||||
f, err := v.getFile(uri)
|
f, err := v.getFile(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -213,19 +233,19 @@ func (v *View) applyContentChange(uri span.URI, content []byte) {
|
||||||
case f.active && content == nil:
|
case f.active && content == nil:
|
||||||
// The file was active, so we need to forget its content.
|
// The file was active, so we need to forget its content.
|
||||||
f.active = false
|
f.active = false
|
||||||
delete(f.view.Config.Overlay, f.filename)
|
delete(f.view.config.Overlay, f.filename)
|
||||||
f.content = nil
|
f.content = nil
|
||||||
case content != nil:
|
case content != nil:
|
||||||
// This is an active overlay, so we update the map.
|
// This is an active overlay, so we update the map.
|
||||||
f.active = true
|
f.active = true
|
||||||
f.view.Config.Overlay[f.filename] = f.content
|
f.view.config.Overlay[f.filename] = f.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove invalidates a package and its reverse dependencies in the view's
|
// remove invalidates a package and its reverse dependencies in the view's
|
||||||
// package cache. It is assumed that the caller has locked both the mutexes
|
// package cache. It is assumed that the caller has locked both the mutexes
|
||||||
// of both the mcache and the pcache.
|
// of both the mcache and the pcache.
|
||||||
func (v *View) remove(pkgPath string, seen map[string]struct{}) {
|
func (v *view) remove(pkgPath string, seen map[string]struct{}) {
|
||||||
if _, ok := seen[pkgPath]; ok {
|
if _, ok := seen[pkgPath]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -248,7 +268,7 @@ func (v *View) remove(pkgPath string, seen map[string]struct{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindFile returns the file if the given URI is already a part of the view.
|
// FindFile returns the file if the given URI is already a part of the view.
|
||||||
func (v *View) FindFile(ctx context.Context, uri span.URI) *File {
|
func (v *view) FindFile(ctx context.Context, uri span.URI) *file {
|
||||||
v.mu.Lock()
|
v.mu.Lock()
|
||||||
defer v.mu.Unlock()
|
defer v.mu.Unlock()
|
||||||
f, err := v.findFile(uri)
|
f, err := v.findFile(uri)
|
||||||
|
@ -260,7 +280,7 @@ func (v *View) FindFile(ctx context.Context, uri span.URI) *File {
|
||||||
|
|
||||||
// GetFile returns a File for the given URI. It will always succeed because it
|
// GetFile returns a File for the given URI. It will always succeed because it
|
||||||
// adds the file to the managed set if needed.
|
// adds the file to the managed set if needed.
|
||||||
func (v *View) GetFile(ctx context.Context, uri span.URI) (source.File, error) {
|
func (v *view) GetFile(ctx context.Context, uri span.URI) (source.File, error) {
|
||||||
v.mu.Lock()
|
v.mu.Lock()
|
||||||
defer v.mu.Unlock()
|
defer v.mu.Unlock()
|
||||||
|
|
||||||
|
@ -272,7 +292,7 @@ func (v *View) GetFile(ctx context.Context, uri span.URI) (source.File, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFile is the unlocked internal implementation of GetFile.
|
// getFile is the unlocked internal implementation of GetFile.
|
||||||
func (v *View) getFile(uri span.URI) (*File, error) {
|
func (v *view) getFile(uri span.URI) (*file, error) {
|
||||||
filename, err := uri.Filename()
|
filename, err := uri.Filename()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -285,7 +305,7 @@ func (v *View) getFile(uri span.URI) (*File, error) {
|
||||||
} else if f != nil {
|
} else if f != nil {
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
f := &File{
|
f := &file{
|
||||||
view: v,
|
view: v,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
}
|
}
|
||||||
|
@ -295,7 +315,7 @@ func (v *View) getFile(uri span.URI) (*File, error) {
|
||||||
|
|
||||||
// isIgnored checks if the given filename is a file we ignore.
|
// isIgnored checks if the given filename is a file we ignore.
|
||||||
// As of right now, we only ignore files in the "builtin" package.
|
// As of right now, we only ignore files in the "builtin" package.
|
||||||
func (v *View) isIgnored(filename string) bool {
|
func (v *view) isIgnored(filename string) bool {
|
||||||
bpkg := v.BuiltinPackage()
|
bpkg := v.BuiltinPackage()
|
||||||
if bpkg != nil {
|
if bpkg != nil {
|
||||||
for builtinFilename := range bpkg.Files {
|
for builtinFilename := range bpkg.Files {
|
||||||
|
@ -311,7 +331,7 @@ func (v *View) isIgnored(filename string) bool {
|
||||||
//
|
//
|
||||||
// An error is only returned for an irreparable failure, for example, if the
|
// An error is only returned for an irreparable failure, for example, if the
|
||||||
// filename in question does not exist.
|
// filename in question does not exist.
|
||||||
func (v *View) findFile(uri span.URI) (*File, error) {
|
func (v *view) findFile(uri span.URI) (*file, error) {
|
||||||
if f := v.filesByURI[uri]; f != nil {
|
if f := v.filesByURI[uri]; f != nil {
|
||||||
// a perfect match
|
// a perfect match
|
||||||
return f, nil
|
return f, nil
|
||||||
|
@ -344,7 +364,7 @@ func (v *View) findFile(uri span.URI) (*File, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) mapFile(uri span.URI, f *File) {
|
func (v *view) mapFile(uri span.URI, f *file) {
|
||||||
v.filesByURI[uri] = f
|
v.filesByURI[uri] = f
|
||||||
f.uris = append(f.uris, uri)
|
f.uris = append(f.uris, uri)
|
||||||
if f.basename == "" {
|
if f.basename == "" {
|
||||||
|
@ -353,6 +373,6 @@ func (v *View) mapFile(uri span.URI, f *File) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) Logger() xlog.Logger {
|
func (v *view) Logger() xlog.Logger {
|
||||||
return v.log
|
return v.log
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,12 @@ package lsp
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/lsp/cache"
|
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) Diagnostics(ctx context.Context, view *cache.View, uri span.URI) {
|
func (s *Server) Diagnostics(ctx context.Context, view source.View, uri span.URI) {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
s.log.Errorf(ctx, "canceling diagnostics for %s: %v", uri, ctx.Err())
|
s.log.Errorf(ctx, "canceling diagnostics for %s: %v", uri, ctx.Err())
|
||||||
return
|
return
|
||||||
|
@ -48,7 +47,7 @@ func (s *Server) Diagnostics(ctx context.Context, view *cache.View, uri span.URI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) publishDiagnostics(ctx context.Context, view *cache.View, uri span.URI, diagnostics []source.Diagnostic) error {
|
func (s *Server) publishDiagnostics(ctx context.Context, view source.View, uri span.URI, diagnostics []source.Diagnostic) error {
|
||||||
protocolDiagnostics, err := toProtocolDiagnostics(ctx, view, diagnostics)
|
protocolDiagnostics, err := toProtocolDiagnostics(ctx, view, diagnostics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -13,8 +13,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/jsonrpc2"
|
"golang.org/x/tools/internal/jsonrpc2"
|
||||||
"golang.org/x/tools/internal/lsp/cache"
|
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
|
||||||
for _, view := range s.views {
|
for _, view := range s.views {
|
||||||
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
|
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
|
||||||
Items: []protocol.ConfigurationItem{{
|
Items: []protocol.ConfigurationItem{{
|
||||||
ScopeURI: protocol.NewURI(view.Folder),
|
ScopeURI: protocol.NewURI(view.Folder()),
|
||||||
Section: "gopls",
|
Section: "gopls",
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
|
@ -146,7 +146,7 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) processConfig(view *cache.View, config interface{}) error {
|
func (s *Server) processConfig(view source.View, config interface{}) error {
|
||||||
// TODO: We should probably store and process more of the config.
|
// TODO: We should probably store and process more of the config.
|
||||||
if config == nil {
|
if config == nil {
|
||||||
return nil // ignore error if you don't have a config
|
return nil // ignore error if you don't have a config
|
||||||
|
@ -162,7 +162,7 @@ func (s *Server) processConfig(view *cache.View, config interface{}) error {
|
||||||
return fmt.Errorf("invalid config gopls.env type %T", env)
|
return fmt.Errorf("invalid config gopls.env type %T", env)
|
||||||
}
|
}
|
||||||
for k, v := range menv {
|
for k, v := range menv {
|
||||||
view.Config.Env = applyEnv(view.Config.Env, k, v)
|
view.SetEnv(applyEnv(view.Config().Env, k, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if placeholders are enabled.
|
// Check if placeholders are enabled.
|
||||||
|
|
|
@ -42,8 +42,8 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
log := xlog.New(xlog.StdSink{})
|
log := xlog.New(xlog.StdSink{})
|
||||||
r := &runner{
|
r := &runner{
|
||||||
server: &Server{
|
server: &Server{
|
||||||
views: []*cache.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
|
views: []source.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
|
||||||
viewMap: make(map[span.URI]*cache.View),
|
viewMap: make(map[span.URI]source.View),
|
||||||
undelivered: make(map[span.URI][]source.Diagnostic),
|
undelivered: make(map[span.URI][]source.Diagnostic),
|
||||||
log: log,
|
log: log,
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/jsonrpc2"
|
"golang.org/x/tools/internal/jsonrpc2"
|
||||||
"golang.org/x/tools/internal/lsp/cache"
|
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/lsp/xlog"
|
"golang.org/x/tools/internal/lsp/xlog"
|
||||||
|
@ -83,8 +82,8 @@ type Server struct {
|
||||||
textDocumentSyncKind protocol.TextDocumentSyncKind
|
textDocumentSyncKind protocol.TextDocumentSyncKind
|
||||||
|
|
||||||
viewMu sync.Mutex
|
viewMu sync.Mutex
|
||||||
views []*cache.View
|
views []source.View
|
||||||
viewMap map[span.URI]*cache.View
|
viewMap map[span.URI]source.View
|
||||||
|
|
||||||
// undelivered is a cache of any diagnostics that the server
|
// undelivered is a cache of any diagnostics that the server
|
||||||
// failed to deliver for some reason.
|
// failed to deliver for some reason.
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestSource(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type runner struct {
|
type runner struct {
|
||||||
view *cache.View
|
view source.View
|
||||||
data *tests.Data
|
data *tests.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,16 @@ import (
|
||||||
// package. The view provides access to files and their contents, so the source
|
// package. The view provides access to files and their contents, so the source
|
||||||
// package does not directly access the file system.
|
// package does not directly access the file system.
|
||||||
type View interface {
|
type View interface {
|
||||||
|
Name() string
|
||||||
|
Folder() span.URI
|
||||||
Logger() xlog.Logger
|
Logger() xlog.Logger
|
||||||
FileSet() *token.FileSet
|
FileSet() *token.FileSet
|
||||||
BuiltinPackage() *ast.Package
|
BuiltinPackage() *ast.Package
|
||||||
GetFile(ctx context.Context, uri span.URI) (File, error)
|
GetFile(ctx context.Context, uri span.URI) (File, error)
|
||||||
SetContent(ctx context.Context, uri span.URI, content []byte) error
|
SetContent(ctx context.Context, uri span.URI, content []byte) error
|
||||||
|
BackgroundContext() context.Context
|
||||||
|
Config() packages.Config
|
||||||
|
SetEnv([]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File represents a Go source file that has been type-checked. It is the input
|
// File represents a Go source file that has been type-checked. It is the input
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
"golang.org/x/tools/internal/lsp/cache"
|
"golang.org/x/tools/internal/lsp/cache"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ func (s *Server) addView(ctx context.Context, name string, uri span.URI) error {
|
||||||
Tests: true,
|
Tests: true,
|
||||||
}))
|
}))
|
||||||
// we always need to drop the view map
|
// we always need to drop the view map
|
||||||
s.viewMap = make(map[span.URI]*cache.View)
|
s.viewMap = make(map[span.URI]source.View)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +68,10 @@ func (s *Server) removeView(ctx context.Context, name string, uri span.URI) erro
|
||||||
s.viewMu.Lock()
|
s.viewMu.Lock()
|
||||||
defer s.viewMu.Unlock()
|
defer s.viewMu.Unlock()
|
||||||
// we always need to drop the view map
|
// we always need to drop the view map
|
||||||
s.viewMap = make(map[span.URI]*cache.View)
|
s.viewMap = make(map[span.URI]source.View)
|
||||||
s.log.Infof(ctx, "drop view %v as %v", name, uri)
|
s.log.Infof(ctx, "drop view %v as %v", name, uri)
|
||||||
for i, view := range s.views {
|
for i, view := range s.views {
|
||||||
if view.Name == name {
|
if view.Name() == name {
|
||||||
// delete this view... we don't care about order but we do want to make
|
// delete this view... we don't care about order but we do want to make
|
||||||
// sure we can garbage collect the view
|
// sure we can garbage collect the view
|
||||||
s.views[i] = s.views[len(s.views)-1]
|
s.views[i] = s.views[len(s.views)-1]
|
||||||
|
@ -85,7 +86,7 @@ func (s *Server) removeView(ctx context.Context, name string, uri span.URI) erro
|
||||||
|
|
||||||
// findView returns the view corresponding to the given URI.
|
// findView returns the view corresponding to the given URI.
|
||||||
// If the file is not already associated with a view, pick one using some heuristics.
|
// If the file is not already associated with a view, pick one using some heuristics.
|
||||||
func (s *Server) findView(ctx context.Context, uri span.URI) *cache.View {
|
func (s *Server) findView(ctx context.Context, uri span.URI) source.View {
|
||||||
s.viewMu.Lock()
|
s.viewMu.Lock()
|
||||||
defer s.viewMu.Unlock()
|
defer s.viewMu.Unlock()
|
||||||
|
|
||||||
|
@ -102,14 +103,14 @@ func (s *Server) findView(ctx context.Context, uri span.URI) *cache.View {
|
||||||
|
|
||||||
// bestView finds the best view to associate a given URI with.
|
// bestView finds the best view to associate a given URI with.
|
||||||
// viewMu must be held when calling this method.
|
// viewMu must be held when calling this method.
|
||||||
func (s *Server) bestView(ctx context.Context, uri span.URI) *cache.View {
|
func (s *Server) bestView(ctx context.Context, uri span.URI) source.View {
|
||||||
// we need to find the best view for this file
|
// we need to find the best view for this file
|
||||||
var longest *cache.View
|
var longest source.View
|
||||||
for _, view := range s.views {
|
for _, view := range s.views {
|
||||||
if longest != nil && len(longest.Folder) > len(view.Folder) {
|
if longest != nil && len(longest.Folder()) > len(view.Folder()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(string(uri), string(view.Folder)) {
|
if strings.HasPrefix(string(uri), string(view.Folder())) {
|
||||||
longest = view
|
longest = view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue