blob: 6d109f7f36b01c8d02b80fcbf3d6f89f3133bd7f [file] [log] [blame]
// Copyright 2018 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/token"
"sync"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/source"
)
type View struct {
mu sync.Mutex // protects all mutable state of the view
Config *packages.Config
files map[source.URI]*File
}
func NewView() *View {
return &View{
Config: &packages.Config{
Mode: packages.LoadSyntax,
Fset: token.NewFileSet(),
Tests: true,
Overlay: make(map[string][]byte),
},
files: make(map[source.URI]*File),
}
}
// GetFile returns a File for the given uri.
// It will always succeed, adding the file to the managed set if needed.
func (v *View) GetFile(uri source.URI) *File {
v.mu.Lock()
f := v.getFile(uri)
v.mu.Unlock()
return f
}
// getFile is the unlocked internal implementation of GetFile.
func (v *View) getFile(uri source.URI) *File {
f, found := v.files[uri]
if !found {
f = &File{
URI: uri,
view: v,
}
v.files[f.URI] = f
}
return f
}
func (v *View) parse(uri source.URI) error {
path, err := uri.Filename()
if err != nil {
return err
}
pkgs, err := packages.Load(v.Config, fmt.Sprintf("file=%s", path))
if len(pkgs) == 0 {
if err == nil {
err = fmt.Errorf("no packages found for %s", path)
}
return err
}
for _, pkg := range pkgs {
// add everything we find to the files cache
for _, fAST := range pkg.Syntax {
// if a file was in multiple packages, which token/ast/pkg do we store
fToken := v.Config.Fset.File(fAST.Pos())
fURI := source.ToURI(fToken.Name())
f := v.getFile(fURI)
f.token = fToken
f.ast = fAST
f.pkg = pkg
}
}
return nil
}