1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:54:43 -07:00

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:
Ian Cottrell 2019-05-14 23:04:23 -04:00
parent 707862fa78
commit ce09bef8aa
12 changed files with 132 additions and 108 deletions

View File

@ -17,7 +17,7 @@ import (
"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()
defer v.mcache.mu.Unlock()
@ -61,9 +61,9 @@ func (v *View) parse(ctx context.Context, f *File) ([]packages.Error, error) {
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) {
cfg := v.Config
cfg := v.config
cfg.Mode = packages.LoadImports | packages.NeedTypesSizes
pkgs, err := packages.Load(&cfg, fmt.Sprintf("file=%s", f.filename))
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
// 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 {
return true
}
// Get file content in case we don't already have it?
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 {
return true
}
@ -113,7 +113,7 @@ func (v *View) reparseImports(ctx context.Context, f *File, filename string) boo
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]
if !ok {
m = &metadata{
@ -156,7 +156,7 @@ func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *me
}
type importer struct {
view *View
view *view
// 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.
@ -193,7 +193,7 @@ func (imp *importer) Import(pkgPath string) (*types.Package, error) {
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]
if !ok {
return nil, fmt.Errorf("no metadata for %v", pkgPath)
@ -205,11 +205,11 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
} else {
typ = types.NewPackage(meta.pkgPath, meta.name)
}
pkg := &Package{
pkg := &pkg{
id: meta.id,
pkgPath: meta.pkgPath,
files: meta.files,
imports: make(map[string]*Package),
imports: make(map[string]*pkg),
types: typ,
typesSizes: meta.typesSizes,
typesInfo: &types.Info{
@ -246,7 +246,7 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
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)
// Add every file in this package to our cache.
@ -255,14 +255,14 @@ func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
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() {
// TODO: If a file is in multiple packages, which package do we store?
if !file.Pos().IsValid() {
v.Logger().Errorf(ctx, "invalid position for file %v", file.Name)
continue
}
tok := v.Config.Fset.File(file.Pos())
tok := v.config.Fset.File(file.Pos())
if tok == nil {
v.Logger().Errorf(ctx, "no token.File for %v", file.Name)
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 {
return
}
@ -325,7 +325,7 @@ func (v *View) appendPkgError(pkg *Package, err error) {
}
case types.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,
Kind: packages.TypeError,
})

View File

@ -16,18 +16,18 @@ import (
"golang.org/x/tools/internal/span"
)
// File holds all the information we know about a file.
type File struct {
// file holds all the information we know about a file.
type file struct {
uris []span.URI
filename string
basename string
view *View
view *view
active bool
content []byte
ast *ast.File
token *token.File
pkg *Package
pkg *pkg
meta *metadata
imports []*ast.ImportSpec
}
@ -36,17 +36,17 @@ func basename(filename string) string {
return strings.ToLower(filepath.Base(filename))
}
func (f *File) URI() span.URI {
func (f *file) URI() span.URI {
return f.uris[0]
}
// View returns the view associated with the file.
func (f *File) View() source.View {
func (f *file) View() source.View {
return f.view
}
// 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()
defer f.view.mu.Unlock()
@ -57,11 +57,11 @@ func (f *File) GetContent(ctx context.Context) []byte {
return f.content
}
func (f *File) GetFileSet(ctx context.Context) *token.FileSet {
return f.view.Config.Fset
func (f *file) GetFileSet(ctx context.Context) *token.FileSet {
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()
defer f.view.mu.Unlock()
@ -73,7 +73,7 @@ func (f *File) GetToken(ctx context.Context) *token.File {
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()
defer f.view.mu.Unlock()
@ -85,7 +85,7 @@ func (f *File) GetAST(ctx context.Context) *ast.File {
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()
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 {
// Create diagnostics for errors if we are able to.
if len(errs) > 0 {
return &Package{errors: errs}
return &pkg{errors: errs}
}
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
// 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 len(f.view.contentChanges) == 0 {
return
@ -118,7 +118,7 @@ func (f *File) read(ctx context.Context) {
}
}
// 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
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.
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
}
func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
func (f *file) GetActiveReverseDeps(ctx context.Context) []source.File {
pkg := f.GetPackage(ctx)
if pkg == nil {
return nil
@ -149,7 +149,7 @@ func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
defer f.view.mcache.mu.Unlock()
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())
files := make([]source.File, 0, len(results))
@ -166,7 +166,7 @@ func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
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 {
return
}

View File

@ -37,9 +37,9 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, filename := range filenames {
if imp.view.Config.Context.Err() != nil {
if imp.view.config.Context.Err() != nil {
parsed[i] = nil
errors[i] = imp.view.Config.Context.Err()
errors[i] = imp.view.config.Context.Err()
continue
}
@ -63,7 +63,7 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
// We don't have a cached AST for this file.
var src []byte
// 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) {
src = contents
}
@ -77,11 +77,11 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
parsed[i], errors[i] = nil, err
} else {
// 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.
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)
}
}
@ -141,7 +141,7 @@ func sameFile(x, y string) bool {
// 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.
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
ast.Inspect(file, func(n ast.Node) bool {
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.
// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST,
// 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".
s := &scanner.Scanner{}
s.Init(tok, src, nil, 0)
@ -260,7 +260,7 @@ FindTo:
// offsetPositions applies an offset to the positions in an ast.Node.
// 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 {
switch n := n.(type) {
case *ast.Ident:

View File

@ -16,13 +16,13 @@ import (
"golang.org/x/tools/internal/lsp/source"
)
// Package contains the type information needed by the source package.
type Package struct {
// pkg contains the type information needed by the source package.
type pkg struct {
id, pkgPath string
files []string
syntax []*ast.File
errors []packages.Error
imports map[string]*Package
imports map[string]*pkg
types *types.Package
typesInfo *types.Info
typesSizes types.Sizes
@ -41,7 +41,7 @@ type analysisEntry struct {
*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 {
return nil, ctx.Err()
}
@ -128,39 +128,39 @@ func (pkg *Package) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*
return e.Action, nil
}
func (pkg *Package) PkgPath() string {
func (pkg *pkg) PkgPath() string {
return pkg.pkgPath
}
func (pkg *Package) GetFilenames() []string {
func (pkg *pkg) GetFilenames() []string {
return pkg.files
}
func (pkg *Package) GetSyntax() []*ast.File {
func (pkg *pkg) GetSyntax() []*ast.File {
return pkg.syntax
}
func (pkg *Package) GetErrors() []packages.Error {
func (pkg *pkg) GetErrors() []packages.Error {
return pkg.errors
}
func (pkg *Package) GetTypes() *types.Package {
func (pkg *pkg) GetTypes() *types.Package {
return pkg.types
}
func (pkg *Package) GetTypesInfo() *types.Info {
func (pkg *pkg) GetTypesInfo() *types.Info {
return pkg.typesInfo
}
func (pkg *Package) GetTypesSizes() types.Sizes {
func (pkg *pkg) GetTypesSizes() types.Sizes {
return pkg.typesSizes
}
func (pkg *Package) IsIllTyped() bool {
func (pkg *pkg) IsIllTyped() bool {
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]
// Be careful not to return a nil pointer because that still satisfies the
// interface.

View File

@ -20,7 +20,7 @@ import (
"golang.org/x/tools/internal/span"
)
type View struct {
type view struct {
// mu protects all mutable state of the view.
mu sync.Mutex
@ -40,19 +40,19 @@ type View struct {
log xlog.Logger
// Name is the user visible name of this view.
Name string
name string
// 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
// 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
// to multiple uris, and the same basename may map to multiple files
filesByURI map[span.URI]*File
filesByBase map[string][]*File
filesByURI map[span.URI]*file
filesByBase map[string][]*file
// 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
@ -89,24 +89,24 @@ type packageCache struct {
}
type entry struct {
pkg *Package
pkg *pkg
err error
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)
v := &View{
v := &view{
baseCtx: ctx,
backgroundCtx: backgroundCtx,
builtinPkg: builtinPkg(*config),
cancel: cancel,
log: log,
Config: *config,
Name: name,
Folder: folder,
filesByURI: make(map[span.URI]*File),
filesByBase: make(map[string][]*File),
config: *config,
name: name,
folder: folder,
filesByURI: make(map[span.URI]*file),
filesByBase: make(map[string][]*file),
contentChanges: make(map[span.URI]func()),
mcache: &metadataCache{
packages: make(map[string]*metadata),
@ -118,14 +118,34 @@ func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI,
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()
defer v.mu.Unlock()
return v.backgroundCtx
}
func (v *View) BuiltinPackage() *ast.Package {
func (v *view) BuiltinPackage() *ast.Package {
return v.builtinPkg
}
@ -151,12 +171,12 @@ func builtinPkg(cfg packages.Config) *ast.Package {
return bpkg
}
func (v *View) FileSet() *token.FileSet {
return v.Config.Fset
func (v *view) FileSet() *token.FileSet {
return v.config.Fset
}
// 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()
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.
// It is assumed that the caller has locked both the view's and the mcache's
// mutexes.
func (v *View) applyContentChanges(ctx context.Context) error {
func (v *view) applyContentChanges(ctx context.Context) error {
if ctx.Err() != nil {
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
// 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)
if err != nil {
return
@ -213,19 +233,19 @@ func (v *View) applyContentChange(uri span.URI, content []byte) {
case f.active && content == nil:
// The file was active, so we need to forget its content.
f.active = false
delete(f.view.Config.Overlay, f.filename)
delete(f.view.config.Overlay, f.filename)
f.content = nil
case content != nil:
// This is an active overlay, so we update the map.
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
// package cache. It is assumed that the caller has locked both the mutexes
// 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 {
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.
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()
defer v.mu.Unlock()
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
// 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()
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.
func (v *View) getFile(uri span.URI) (*File, error) {
func (v *view) getFile(uri span.URI) (*file, error) {
filename, err := uri.Filename()
if err != nil {
return nil, err
@ -285,7 +305,7 @@ func (v *View) getFile(uri span.URI) (*File, error) {
} else if f != nil {
return f, nil
}
f := &File{
f := &file{
view: v,
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.
// 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()
if bpkg != nil {
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
// 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 {
// a perfect match
return f, nil
@ -344,7 +364,7 @@ func (v *View) findFile(uri span.URI) (*File, error) {
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
f.uris = append(f.uris, uri)
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
}

View File

@ -7,13 +7,12 @@ package lsp
import (
"context"
"golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"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 {
s.log.Errorf(ctx, "canceling diagnostics for %s: %v", uri, ctx.Err())
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)
if err != nil {
return err

View File

@ -13,8 +13,8 @@ import (
"strings"
"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/source"
"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 {
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
Items: []protocol.ConfigurationItem{{
ScopeURI: protocol.NewURI(view.Folder),
ScopeURI: protocol.NewURI(view.Folder()),
Section: "gopls",
}},
})
@ -146,7 +146,7 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
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.
if config == nil {
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)
}
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.

View File

@ -42,8 +42,8 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
log := xlog.New(xlog.StdSink{})
r := &runner{
server: &Server{
views: []*cache.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
viewMap: make(map[span.URI]*cache.View),
views: []source.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
viewMap: make(map[span.URI]source.View),
undelivered: make(map[span.URI][]source.Diagnostic),
log: log,
},

View File

@ -11,7 +11,6 @@ import (
"sync"
"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/source"
"golang.org/x/tools/internal/lsp/xlog"
@ -83,8 +82,8 @@ type Server struct {
textDocumentSyncKind protocol.TextDocumentSyncKind
viewMu sync.Mutex
views []*cache.View
viewMap map[span.URI]*cache.View
views []source.View
viewMap map[span.URI]source.View
// undelivered is a cache of any diagnostics that the server
// failed to deliver for some reason.

View File

@ -27,7 +27,7 @@ func TestSource(t *testing.T) {
}
type runner struct {
view *cache.View
view source.View
data *tests.Data
}

View File

@ -22,11 +22,16 @@ import (
// package. The view provides access to files and their contents, so the source
// package does not directly access the file system.
type View interface {
Name() string
Folder() span.URI
Logger() xlog.Logger
FileSet() *token.FileSet
BuiltinPackage() *ast.Package
GetFile(ctx context.Context, uri span.URI) (File, 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

View File

@ -16,6 +16,7 @@ import (
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"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,
}))
// 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
}
@ -67,10 +68,10 @@ func (s *Server) removeView(ctx context.Context, name string, uri span.URI) erro
s.viewMu.Lock()
defer s.viewMu.Unlock()
// 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)
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
// sure we can garbage collect the view
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.
// 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()
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.
// 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
var longest *cache.View
var longest source.View
for _, view := range s.views {
if longest != nil && len(longest.Folder) > len(view.Folder) {
if longest != nil && len(longest.Folder()) > len(view.Folder()) {
continue
}
if strings.HasPrefix(string(uri), string(view.Folder)) {
if strings.HasPrefix(string(uri), string(view.Folder())) {
longest = view
}
}