mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
internal/lsp: prepare for non go files
This abstracts out the concrete file type so that we can support non go files. Change-Id: I7447daa2ce076ec2867de9e59a0dedfe1a0553f5 Reviewed-on: https://go-review.googlesource.com/c/tools/+/175217 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
0e55654012
commit
4f9510c6a1
48
internal/lsp/cache/check.go
vendored
48
internal/lsp/cache/check.go
vendored
@ -14,10 +14,11 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"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, file source.File) ([]packages.Error, error) {
|
||||||
v.mcache.mu.Lock()
|
v.mcache.mu.Lock()
|
||||||
defer v.mcache.mu.Unlock()
|
defer v.mcache.mu.Unlock()
|
||||||
|
|
||||||
@ -26,6 +27,11 @@ func (v *view) parse(ctx context.Context, f *file) ([]packages.Error, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f, ok := file.(*goFile)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("not a go file: %v", file.URI())
|
||||||
|
}
|
||||||
|
|
||||||
// If the package for the file has not been invalidated by the application
|
// If the package for the file has not been invalidated by the application
|
||||||
// of the pending changes, there is no need to continue.
|
// of the pending changes, there is no need to continue.
|
||||||
if f.isPopulated() {
|
if f.isPopulated() {
|
||||||
@ -37,7 +43,7 @@ func (v *view) parse(ctx context.Context, f *file) ([]packages.Error, error) {
|
|||||||
return errs, err
|
return errs, err
|
||||||
}
|
}
|
||||||
if f.meta == nil {
|
if f.meta == nil {
|
||||||
return nil, fmt.Errorf("no metadata found for %v", f.filename)
|
return nil, fmt.Errorf("no metadata found for %v", f.filename())
|
||||||
}
|
}
|
||||||
imp := &importer{
|
imp := &importer{
|
||||||
view: v,
|
view: v,
|
||||||
@ -56,19 +62,19 @@ func (v *view) parse(ctx context.Context, f *file) ([]packages.Error, error) {
|
|||||||
|
|
||||||
// If we still have not found the package for the file, something is wrong.
|
// If we still have not found the package for the file, something is wrong.
|
||||||
if f.pkg == nil {
|
if f.pkg == nil {
|
||||||
return nil, fmt.Errorf("parse: no package found for %v", f.filename)
|
return nil, fmt.Errorf("parse: no package found for %v", f.filename())
|
||||||
}
|
}
|
||||||
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 *goFile) ([]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 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("no packages found for %s", f.filename)
|
err = fmt.Errorf("no packages found for %s", f.filename())
|
||||||
}
|
}
|
||||||
// Return this error as a diagnostic to the user.
|
// Return this error as a diagnostic to the user.
|
||||||
return []packages.Error{
|
return []packages.Error{
|
||||||
@ -84,7 +90,7 @@ func (v *view) checkMetadata(ctx context.Context, f *file) ([]packages.Error, er
|
|||||||
if len(pkg.Errors) > 0 {
|
if len(pkg.Errors) > 0 {
|
||||||
return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
|
return pkg.Errors, fmt.Errorf("package %s has errors, skipping type-checking", pkg.PkgPath)
|
||||||
}
|
}
|
||||||
v.link(pkg.PkgPath, pkg, nil)
|
v.link(ctx, pkg.PkgPath, pkg, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -92,7 +98,7 @@ 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 *goFile, filename string) bool {
|
||||||
if f.meta == nil {
|
if f.meta == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -113,7 +119,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(ctx context.Context, 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{
|
||||||
@ -130,7 +136,12 @@ func (v *view) link(pkgPath string, pkg *packages.Package, parent *metadata) *me
|
|||||||
m.files = pkg.CompiledGoFiles
|
m.files = pkg.CompiledGoFiles
|
||||||
for _, filename := range m.files {
|
for _, filename := range m.files {
|
||||||
if f, _ := v.getFile(span.FileURI(filename)); f != nil {
|
if f, _ := v.getFile(span.FileURI(filename)); f != nil {
|
||||||
f.meta = m
|
gof, ok := f.(*goFile)
|
||||||
|
if !ok {
|
||||||
|
v.Logger().Errorf(ctx, "not a go file: %v", f.URI())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gof.meta = m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Connect the import graph.
|
// Connect the import graph.
|
||||||
@ -140,7 +151,7 @@ func (v *view) link(pkgPath string, pkg *packages.Package, parent *metadata) *me
|
|||||||
}
|
}
|
||||||
for importPath, importPkg := range pkg.Imports {
|
for importPath, importPkg := range pkg.Imports {
|
||||||
if _, ok := m.children[importPath]; !ok {
|
if _, ok := m.children[importPath]; !ok {
|
||||||
v.link(importPath, importPkg, m)
|
v.link(ctx, importPath, importPkg, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear out any imports that have been removed.
|
// Clear out any imports that have been removed.
|
||||||
@ -273,10 +284,15 @@ func (v *view) cachePackage(ctx context.Context, pkg *pkg, meta *metadata) {
|
|||||||
v.Logger().Errorf(ctx, "no file: %v", err)
|
v.Logger().Errorf(ctx, "no file: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.token = tok
|
gof, ok := f.(*goFile)
|
||||||
f.ast = file
|
if !ok {
|
||||||
f.imports = f.ast.Imports
|
v.Logger().Errorf(ctx, "not a go file: %v", f.URI())
|
||||||
f.pkg = pkg
|
continue
|
||||||
|
}
|
||||||
|
gof.token = tok
|
||||||
|
gof.ast = file
|
||||||
|
gof.imports = gof.ast.Imports
|
||||||
|
gof.pkg = pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
v.pcache.mu.Lock()
|
v.pcache.mu.Lock()
|
||||||
|
72
internal/lsp/cache/file.go
vendored
72
internal/lsp/cache/file.go
vendored
@ -16,17 +16,32 @@ import (
|
|||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
// file holds all the information we know about a file.
|
// viewFile extends source.File with helper methods for the view package.
|
||||||
type file struct {
|
type viewFile interface {
|
||||||
uris []span.URI
|
source.File
|
||||||
filename string
|
setContent(content []byte)
|
||||||
basename string
|
filename() string
|
||||||
|
addURI(uri span.URI) int
|
||||||
|
isActive() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileBase holds the common functionality for all files.
|
||||||
|
// It is intended to be embedded in the file implementations
|
||||||
|
type fileBase struct {
|
||||||
|
uris []span.URI
|
||||||
|
fname string
|
||||||
|
|
||||||
view *view
|
view *view
|
||||||
active bool
|
active bool
|
||||||
content []byte
|
content []byte
|
||||||
ast *ast.File
|
|
||||||
token *token.File
|
token *token.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// goFile holds all the information we know about a go file.
|
||||||
|
type goFile struct {
|
||||||
|
fileBase
|
||||||
|
|
||||||
|
ast *ast.File
|
||||||
pkg *pkg
|
pkg *pkg
|
||||||
meta *metadata
|
meta *metadata
|
||||||
imports []*ast.ImportSpec
|
imports []*ast.ImportSpec
|
||||||
@ -36,17 +51,25 @@ 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 *fileBase) URI() span.URI {
|
||||||
return f.uris[0]
|
return f.uris[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fileBase) filename() string {
|
||||||
|
return f.fname
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileBase) isActive() bool {
|
||||||
|
return f.active
|
||||||
|
}
|
||||||
|
|
||||||
// View returns the view associated with the file.
|
// View returns the view associated with the file.
|
||||||
func (f *file) View() source.View {
|
func (f *fileBase) 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 *fileBase) GetContent(ctx context.Context) []byte {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
@ -57,14 +80,13 @@ 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 *fileBase) 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 *goFile) GetToken(ctx context.Context) *token.File {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
if f.token == nil || len(f.view.contentChanges) > 0 {
|
if f.token == nil || len(f.view.contentChanges) > 0 {
|
||||||
if _, err := f.view.parse(ctx, f); err != nil {
|
if _, err := f.view.parse(ctx, f); err != nil {
|
||||||
return nil
|
return nil
|
||||||
@ -73,7 +95,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 *goFile) 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 +107,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 *goFile) GetPackage(ctx context.Context) source.Package {
|
||||||
f.view.mu.Lock()
|
f.view.mu.Lock()
|
||||||
defer f.view.mu.Unlock()
|
defer f.view.mu.Unlock()
|
||||||
|
|
||||||
@ -103,7 +125,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 *fileBase) 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,25 +140,25 @@ 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
|
||||||
}
|
}
|
||||||
// We don't know the content yet, so read it.
|
// We don't know the content yet, so read it.
|
||||||
content, err := ioutil.ReadFile(f.filename)
|
content, err := ioutil.ReadFile(f.filename())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.view.Logger().Errorf(ctx, "unable to read file %s: %v", f.filename, err)
|
f.view.Logger().Errorf(ctx, "unable to read file %s: %v", f.filename(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.content = content
|
f.content = content
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *goFile) 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 *goFile) GetActiveReverseDeps(ctx context.Context) []source.GoFile {
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -149,10 +171,10 @@ 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[*goFile]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.GoFile, 0, len(results))
|
||||||
for rd := range results {
|
for rd := range results {
|
||||||
if rd == nil {
|
if rd == nil {
|
||||||
continue
|
continue
|
||||||
@ -166,7 +188,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[*goFile]struct{}, pkgPath string) {
|
||||||
if _, ok := seen[pkgPath]; ok {
|
if _, ok := seen[pkgPath]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -176,8 +198,8 @@ func (v *view) reverseDeps(ctx context.Context, seen map[string]struct{}, result
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, filename := range m.files {
|
for _, filename := range m.files {
|
||||||
if f, err := v.getFile(span.FileURI(filename)); err == nil && f.active {
|
if f, err := v.getFile(span.FileURI(filename)); err == nil && f.isActive() {
|
||||||
results[f] = struct{}{}
|
results[f.(*goFile)] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for parentPkgPath := range m.parents {
|
for parentPkgPath := range m.parents {
|
||||||
|
4
internal/lsp/cache/parse.go
vendored
4
internal/lsp/cache/parse.go
vendored
@ -50,7 +50,9 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
|
|||||||
}
|
}
|
||||||
var fAST *ast.File
|
var fAST *ast.File
|
||||||
if f != nil {
|
if f != nil {
|
||||||
fAST = f.ast
|
if gof, ok := f.(*goFile); ok {
|
||||||
|
fAST = gof.ast
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
52
internal/lsp/cache/view.go
vendored
52
internal/lsp/cache/view.go
vendored
@ -51,8 +51,8 @@ type view struct {
|
|||||||
|
|
||||||
// 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]viewFile
|
||||||
filesByBase map[string][]*file
|
filesByBase map[string][]viewFile
|
||||||
|
|
||||||
// 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
|
||||||
@ -105,8 +105,8 @@ func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI,
|
|||||||
config: *config,
|
config: *config,
|
||||||
name: name,
|
name: name,
|
||||||
folder: folder,
|
folder: folder,
|
||||||
filesByURI: make(map[span.URI]*file),
|
filesByURI: make(map[span.URI]viewFile),
|
||||||
filesByBase: make(map[string][]*file),
|
filesByBase: make(map[string][]viewFile),
|
||||||
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),
|
||||||
@ -227,6 +227,10 @@ func (v *view) applyContentChange(uri span.URI, content []byte) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
f.setContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *goFile) setContent(content []byte) {
|
||||||
f.content = content
|
f.content = content
|
||||||
|
|
||||||
// TODO(rstambler): Should we recompute these here?
|
// TODO(rstambler): Should we recompute these here?
|
||||||
@ -235,19 +239,19 @@ func (v *view) applyContentChange(uri span.URI, content []byte) {
|
|||||||
|
|
||||||
// Remove the package and all of its reverse dependencies from the cache.
|
// Remove the package and all of its reverse dependencies from the cache.
|
||||||
if f.pkg != nil {
|
if f.pkg != nil {
|
||||||
v.remove(f.pkg.pkgPath, map[string]struct{}{})
|
f.view.remove(f.pkg.pkgPath, map[string]struct{}{})
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,14 +274,16 @@ func (v *view) remove(pkgPath string, seen map[string]struct{}) {
|
|||||||
// invalidated package.
|
// invalidated package.
|
||||||
for _, filename := range m.files {
|
for _, filename := range m.files {
|
||||||
if f, _ := v.findFile(span.FileURI(filename)); f != nil {
|
if f, _ := v.findFile(span.FileURI(filename)); f != nil {
|
||||||
f.pkg = nil
|
if gof, ok := f.(*goFile); ok {
|
||||||
|
gof.pkg = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(v.pcache.packages, pkgPath)
|
delete(v.pcache.packages, pkgPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) source.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)
|
||||||
@ -301,7 +307,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) (viewFile, error) {
|
||||||
filename, err := uri.Filename()
|
filename, err := uri.Filename()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -314,9 +320,11 @@ 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 := &goFile{
|
||||||
view: v,
|
fileBase: fileBase{
|
||||||
filename: filename,
|
view: v,
|
||||||
|
fname: filename,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
v.mapFile(uri, f)
|
v.mapFile(uri, f)
|
||||||
return f, nil
|
return f, nil
|
||||||
@ -340,7 +348,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) (viewFile, 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
|
||||||
@ -360,7 +368,7 @@ func (v *view) findFile(uri span.URI) (*file, error) {
|
|||||||
return nil, nil // the file may exist, return without an error
|
return nil, nil // the file may exist, return without an error
|
||||||
}
|
}
|
||||||
for _, c := range candidates {
|
for _, c := range candidates {
|
||||||
if cStat, err := os.Stat(c.filename); err == nil {
|
if cStat, err := os.Stat(c.filename()); err == nil {
|
||||||
if os.SameFile(pathStat, cStat) {
|
if os.SameFile(pathStat, cStat) {
|
||||||
// same file, map it
|
// same file, map it
|
||||||
v.mapFile(uri, c)
|
v.mapFile(uri, c)
|
||||||
@ -373,12 +381,16 @@ 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 (f *fileBase) addURI(uri span.URI) int {
|
||||||
v.filesByURI[uri] = f
|
|
||||||
f.uris = append(f.uris, uri)
|
f.uris = append(f.uris, uri)
|
||||||
if f.basename == "" {
|
return len(f.uris)
|
||||||
f.basename = basename(f.filename)
|
}
|
||||||
v.filesByBase[f.basename] = append(v.filesByBase[f.basename], f)
|
|
||||||
|
func (v *view) mapFile(uri span.URI, f viewFile) {
|
||||||
|
v.filesByURI[uri] = f
|
||||||
|
if f.addURI(uri) == 1 {
|
||||||
|
basename := basename(f.filename())
|
||||||
|
v.filesByBase[basename] = append(v.filesByBase[basename], f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
_, m, err := newColumnMap(ctx, view, uri)
|
_, m, err := getSourceFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
|
|||||||
}
|
}
|
||||||
|
|
||||||
func organizeImports(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, error) {
|
func organizeImports(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, error) {
|
||||||
f, m, err := newColumnMap(ctx, v, s.URI())
|
f, m, err := getGoFile(ctx, v, s.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
|
func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, decM, err := newColumnMap(ctx, view, decSpan.URI())
|
_, decM, err := getSourceFile(ctx, view, decSpan.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPo
|
|||||||
func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocume
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, identM, err := newColumnMap(ctx, view, identSpan.URI())
|
_, identM, err := getSourceFile(ctx, view, identSpan.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func (s *Server) publishDiagnostics(ctx context.Context, view source.View, uri s
|
|||||||
func toProtocolDiagnostics(ctx context.Context, v source.View, diagnostics []source.Diagnostic) ([]protocol.Diagnostic, error) {
|
func toProtocolDiagnostics(ctx context.Context, v source.View, diagnostics []source.Diagnostic) ([]protocol.Diagnostic, error) {
|
||||||
reports := []protocol.Diagnostic{}
|
reports := []protocol.Diagnostic{}
|
||||||
for _, diag := range diagnostics {
|
for _, diag := range diagnostics {
|
||||||
_, m, err := newColumnMap(ctx, v, diag.Span.URI())
|
_, m, err := getSourceFile(ctx, v, diag.Span.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormat
|
|||||||
|
|
||||||
// formatRange formats a document with a given range.
|
// formatRange formats a document with a given range.
|
||||||
func formatRange(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, error) {
|
func formatRange(ctx context.Context, v source.View, s span.Span) ([]protocol.TextEdit, error) {
|
||||||
f, m, err := newColumnMap(ctx, v, s.URI())
|
f, m, err := getGoFile(ctx, v, s.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func (s *Server) documentHighlight(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
func (s *Server) documentHighlight(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.Hover, error) {
|
func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.Hover, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, m, err := newColumnMap(ctx, r.server.findView(ctx, uri), uri)
|
_, m, err := getSourceFile(ctx, r.server.findView(ctx, uri), uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func (s *Server) signatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
func (s *Server) signatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ func (c *completer) found(obj types.Object, weight float64) {
|
|||||||
// The prefix is computed based on the preceding identifier and can be used by
|
// The prefix is computed based on the preceding identifier and can be used by
|
||||||
// the client to score the quality of the completion. For instance, some clients
|
// the client to score the quality of the completion. For instance, some clients
|
||||||
// may tolerate imperfect matches as valid completion results, since users may make typos.
|
// may tolerate imperfect matches as valid completion results, since users may make typos.
|
||||||
func Completion(ctx context.Context, f File, pos token.Pos) ([]CompletionItem, Prefix, error) {
|
func Completion(ctx context.Context, f GoFile, pos token.Pos) ([]CompletionItem, Prefix, error) {
|
||||||
file := f.GetAST(ctx)
|
file := f.GetAST(ctx)
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil || pkg.IsIllTyped() {
|
if pkg == nil || pkg.IsIllTyped() {
|
||||||
|
@ -55,7 +55,11 @@ func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diag
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return singleDiagnostic(uri, "no file found for %s", uri), nil
|
return singleDiagnostic(uri, "no file found for %s", uri), nil
|
||||||
}
|
}
|
||||||
pkg := f.GetPackage(ctx)
|
gof, ok := f.(GoFile)
|
||||||
|
if !ok {
|
||||||
|
return singleDiagnostic(uri, "%s is not a go file", uri), nil
|
||||||
|
}
|
||||||
|
pkg := gof.GetPackage(ctx)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return singleDiagnostic(uri, "%s is not part of a package", uri), nil
|
return singleDiagnostic(uri, "%s is not part of a package", uri), nil
|
||||||
}
|
}
|
||||||
@ -72,7 +76,7 @@ func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Updates to the diagnostics for this package may need to be propagated.
|
// Updates to the diagnostics for this package may need to be propagated.
|
||||||
for _, f := range f.GetActiveReverseDeps(ctx) {
|
for _, f := range gof.GetActiveReverseDeps(ctx) {
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
continue
|
continue
|
||||||
@ -151,11 +155,16 @@ func analyses(ctx context.Context, v View, pkg Package, reports map[span.URI][]D
|
|||||||
|
|
||||||
func pointToSpan(ctx context.Context, v View, spn span.Span) span.Span {
|
func pointToSpan(ctx context.Context, v View, spn span.Span) span.Span {
|
||||||
// Don't set a range if it's anything other than a type error.
|
// Don't set a range if it's anything other than a type error.
|
||||||
diagFile, err := v.GetFile(ctx, spn.URI())
|
f, err := v.GetFile(ctx, spn.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
v.Logger().Errorf(ctx, "Could find file for diagnostic: %v", spn.URI())
|
v.Logger().Errorf(ctx, "Could find file for diagnostic: %v", spn.URI())
|
||||||
return spn
|
return spn
|
||||||
}
|
}
|
||||||
|
diagFile, ok := f.(GoFile)
|
||||||
|
if !ok {
|
||||||
|
v.Logger().Errorf(ctx, "Not a go file: %v", spn.URI())
|
||||||
|
return spn
|
||||||
|
}
|
||||||
tok := diagFile.GetToken(ctx)
|
tok := diagFile.GetToken(ctx)
|
||||||
if tok == nil {
|
if tok == nil {
|
||||||
v.Logger().Errorf(ctx, "Could not find tokens for diagnostic: %v", spn.URI())
|
v.Logger().Errorf(ctx, "Could not find tokens for diagnostic: %v", spn.URI())
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Format formats a file with a given range.
|
// Format formats a file with a given range.
|
||||||
func Format(ctx context.Context, f File, rng span.Range) ([]TextEdit, error) {
|
func Format(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error) {
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if hasParseErrors(pkg.GetErrors()) {
|
if hasParseErrors(pkg.GetErrors()) {
|
||||||
return nil, fmt.Errorf("%s has parse errors, not formatting", f.URI())
|
return nil, fmt.Errorf("%s has parse errors, not formatting", f.URI())
|
||||||
@ -52,7 +52,7 @@ func hasParseErrors(errors []packages.Error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Imports formats a file using the goimports tool.
|
// Imports formats a file using the goimports tool.
|
||||||
func Imports(ctx context.Context, f File, rng span.Range) ([]TextEdit, error) {
|
func Imports(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error) {
|
||||||
formatted, err := imports.Process(f.GetToken(ctx).Name(), f.GetContent(ctx), nil)
|
formatted, err := imports.Process(f.GetToken(ctx).Name(), f.GetContent(ctx), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Highlight(ctx context.Context, f File, pos token.Pos) []span.Span {
|
func Highlight(ctx context.Context, f GoFile, pos token.Pos) []span.Span {
|
||||||
fAST := f.GetAST(ctx)
|
fAST := f.GetAST(ctx)
|
||||||
fset := f.GetFileSet(ctx)
|
fset := f.GetFileSet(ctx)
|
||||||
path, _ := astutil.PathEnclosingInterval(fAST, pos, pos)
|
path, _ := astutil.PathEnclosingInterval(fAST, pos, pos)
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
type IdentifierInfo struct {
|
type IdentifierInfo struct {
|
||||||
Name string
|
Name string
|
||||||
Range span.Range
|
Range span.Range
|
||||||
File File
|
File GoFile
|
||||||
Type struct {
|
Type struct {
|
||||||
Range span.Range
|
Range span.Range
|
||||||
Object types.Object
|
Object types.Object
|
||||||
@ -37,7 +37,7 @@ type IdentifierInfo struct {
|
|||||||
|
|
||||||
// Identifier returns identifier information for a position
|
// Identifier returns identifier information for a position
|
||||||
// in a file, accounting for a potentially incomplete selector.
|
// in a file, accounting for a potentially incomplete selector.
|
||||||
func Identifier(ctx context.Context, v View, f File, pos token.Pos) (*IdentifierInfo, error) {
|
func Identifier(ctx context.Context, v View, f GoFile, pos token.Pos) (*IdentifierInfo, error) {
|
||||||
if result, err := identifier(ctx, v, f, pos); err != nil || result != nil {
|
if result, err := identifier(ctx, v, f, pos); err != nil || result != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ func Identifier(ctx context.Context, v View, f File, pos token.Pos) (*Identifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
// identifier checks a single position for a potential identifier.
|
// identifier checks a single position for a potential identifier.
|
||||||
func identifier(ctx context.Context, v View, f File, pos token.Pos) (*IdentifierInfo, error) {
|
func identifier(ctx context.Context, v View, f GoFile, pos token.Pos) (*IdentifierInfo, error) {
|
||||||
fAST := f.GetAST(ctx)
|
fAST := f.GetAST(ctx)
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil || pkg.IsIllTyped() {
|
if pkg == nil || pkg.IsIllTyped() {
|
||||||
@ -128,7 +128,7 @@ func identifier(ctx context.Context, v View, f File, pos token.Pos) (*Identifier
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkImportSpec(f File, fAST *ast.File, pkg Package, pos token.Pos) (*IdentifierInfo, error) {
|
func checkImportSpec(f GoFile, fAST *ast.File, pkg Package, pos token.Pos) (*IdentifierInfo, error) {
|
||||||
// Check if pos is in an *ast.ImportSpec.
|
// Check if pos is in an *ast.ImportSpec.
|
||||||
for _, imp := range fAST.Imports {
|
for _, imp := range fAST.Imports {
|
||||||
if imp.Pos() <= pos && pos < imp.End() {
|
if imp.Pos() <= pos && pos < imp.End() {
|
||||||
@ -204,10 +204,14 @@ func objToNode(ctx context.Context, v View, obj types.Object, rng span.Range) (a
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
declFile, err := v.GetFile(ctx, s.URI())
|
f, err := v.GetFile(ctx, s.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
declFile, ok := f.(GoFile)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("not a go file %v", s.URI())
|
||||||
|
}
|
||||||
declAST := declFile.GetAST(ctx)
|
declAST := declFile.GetAST(ctx)
|
||||||
path, _ := astutil.PathEnclosingInterval(declAST, rng.Start, rng.End)
|
path, _ := astutil.PathEnclosingInterval(declAST, rng.Start, rng.End)
|
||||||
if path == nil {
|
if path == nil {
|
||||||
|
@ -24,7 +24,7 @@ type ParameterInformation struct {
|
|||||||
Label string
|
Label string
|
||||||
}
|
}
|
||||||
|
|
||||||
func SignatureHelp(ctx context.Context, f File, pos token.Pos) (*SignatureInformation, error) {
|
func SignatureHelp(ctx context.Context, f GoFile, pos token.Pos) (*SignatureInformation, error) {
|
||||||
fAST := f.GetAST(ctx)
|
fAST := f.GetAST(ctx)
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil || pkg.IsIllTyped() {
|
if pkg == nil || pkg.IsIllTyped() {
|
||||||
|
@ -133,9 +133,9 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", src, err)
|
t.Fatalf("failed for %v: %v", src, err)
|
||||||
}
|
}
|
||||||
tok := f.GetToken(ctx)
|
tok := f.(source.GoFile).GetToken(ctx)
|
||||||
pos := tok.Pos(src.Start().Offset())
|
pos := tok.Pos(src.Start().Offset())
|
||||||
list, prefix, err := source.Completion(ctx, f, pos)
|
list, prefix, err := source.Completion(ctx, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", src, err)
|
t.Fatalf("failed for %v: %v", src, err)
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests
|
|||||||
}
|
}
|
||||||
tok := f.GetToken(ctx)
|
tok := f.GetToken(ctx)
|
||||||
pos := tok.Pos(src.Start().Offset())
|
pos := tok.Pos(src.Start().Offset())
|
||||||
list, _, err := source.Completion(ctx, f, pos)
|
list, _, err := source.Completion(ctx, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", src, err)
|
t.Fatalf("failed for %v: %v", src, err)
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", spn, err)
|
t.Fatalf("failed for %v: %v", spn, err)
|
||||||
}
|
}
|
||||||
edits, err := source.Format(ctx, f, rng)
|
edits, err := source.Format(ctx, f.(source.GoFile), rng)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if gofmted != "" {
|
if gofmted != "" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -297,7 +297,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
|||||||
}
|
}
|
||||||
tok := f.GetToken(ctx)
|
tok := f.GetToken(ctx)
|
||||||
pos := tok.Pos(d.Src.Start().Offset())
|
pos := tok.Pos(d.Src.Start().Offset())
|
||||||
ident, err := source.Identifier(ctx, r.view, f, pos)
|
ident, err := source.Identifier(ctx, r.view, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||||
}
|
}
|
||||||
@ -341,7 +341,7 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
|||||||
}
|
}
|
||||||
tok := f.GetToken(ctx)
|
tok := f.GetToken(ctx)
|
||||||
pos := tok.Pos(src.Start().Offset())
|
pos := tok.Pos(src.Start().Offset())
|
||||||
highlights := source.Highlight(ctx, f, pos)
|
highlights := source.Highlight(ctx, f.(source.GoFile), pos)
|
||||||
if len(highlights) != len(locations) {
|
if len(highlights) != len(locations) {
|
||||||
t.Fatalf("got %d highlights for %s, expected %d", len(highlights), name, len(locations))
|
t.Fatalf("got %d highlights for %s, expected %d", len(highlights), name, len(locations))
|
||||||
}
|
}
|
||||||
@ -360,7 +360,7 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", uri, err)
|
t.Fatalf("failed for %v: %v", uri, err)
|
||||||
}
|
}
|
||||||
symbols := source.DocumentSymbols(ctx, f)
|
symbols := source.DocumentSymbols(ctx, f.(source.GoFile))
|
||||||
|
|
||||||
if len(symbols) != len(expectedSymbols) {
|
if len(symbols) != len(expectedSymbols) {
|
||||||
t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
|
t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
|
||||||
@ -424,7 +424,7 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
|||||||
}
|
}
|
||||||
tok := f.GetToken(ctx)
|
tok := f.GetToken(ctx)
|
||||||
pos := tok.Pos(spn.Start().Offset())
|
pos := tok.Pos(spn.Start().Offset())
|
||||||
gotSignature, err := source.SignatureHelp(ctx, f, pos)
|
gotSignature, err := source.SignatureHelp(ctx, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", spn, err)
|
t.Fatalf("failed for %v: %v", spn, err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ type Symbol struct {
|
|||||||
Children []Symbol
|
Children []Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func DocumentSymbols(ctx context.Context, f File) []Symbol {
|
func DocumentSymbols(ctx context.Context, f GoFile) []Symbol {
|
||||||
fset := f.GetFileSet(ctx)
|
fset := f.GetFileSet(ctx)
|
||||||
file := f.GetAST(ctx)
|
file := f.GetAST(ctx)
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
|
@ -35,22 +35,24 @@ type View interface {
|
|||||||
Shutdown(ctx context.Context)
|
Shutdown(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File represents a Go source file that has been type-checked. It is the input
|
// File represents a source file of any type.
|
||||||
// to most of the exported functions in this package, as it wraps up the
|
|
||||||
// building blocks for most queries. Users of the source package can abstract
|
|
||||||
// the loading of packages into their own caching systems.
|
|
||||||
type File interface {
|
type File interface {
|
||||||
URI() span.URI
|
URI() span.URI
|
||||||
View() View
|
View() View
|
||||||
GetAST(ctx context.Context) *ast.File
|
|
||||||
GetFileSet(ctx context.Context) *token.FileSet
|
|
||||||
GetPackage(ctx context.Context) Package
|
|
||||||
GetToken(ctx context.Context) *token.File
|
|
||||||
GetContent(ctx context.Context) []byte
|
GetContent(ctx context.Context) []byte
|
||||||
|
GetFileSet(ctx context.Context) *token.FileSet
|
||||||
|
GetToken(ctx context.Context) *token.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoFile represents a Go source file that has been type-checked.
|
||||||
|
type GoFile interface {
|
||||||
|
File
|
||||||
|
GetAST(ctx context.Context) *ast.File
|
||||||
|
GetPackage(ctx context.Context) Package
|
||||||
|
|
||||||
// GetActiveReverseDeps returns the active files belonging to the reverse
|
// GetActiveReverseDeps returns the active files belonging to the reverse
|
||||||
// dependencies of this file's package.
|
// dependencies of this file's package.
|
||||||
GetActiveReverseDeps(ctx context.Context) []File
|
GetActiveReverseDeps(ctx context.Context) []GoFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// Package represents a Go package that has been type-checked. It maintains
|
// Package represents a Go package that has been type-checked. It maintains
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
f, m, err := newColumnMap(ctx, view, uri)
|
f, m, err := getGoFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func (s *Server) applyChanges(ctx context.Context, params *protocol.DidChangeTex
|
|||||||
|
|
||||||
uri := span.NewURI(params.TextDocument.URI)
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
view := s.findView(ctx, uri)
|
view := s.findView(ctx, uri)
|
||||||
file, m, err := newColumnMap(ctx, view, uri)
|
file, m, err := getSourceFile(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "file not found")
|
return "", jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "file not found")
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func PrintVersionInfo(w io.Writer, verbose bool, markdown bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newColumnMap(ctx context.Context, v source.View, uri span.URI) (source.File, *protocol.ColumnMapper, error) {
|
func getSourceFile(ctx context.Context, v source.View, uri span.URI) (source.File, *protocol.ColumnMapper, error) {
|
||||||
f, err := v.GetFile(ctx, uri)
|
f, err := v.GetFile(ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -58,3 +58,15 @@ func newColumnMap(ctx context.Context, v source.View, uri span.URI) (source.File
|
|||||||
m := protocol.NewColumnMapper(f.URI(), f.GetFileSet(ctx), tok, f.GetContent(ctx))
|
m := protocol.NewColumnMapper(f.URI(), f.GetFileSet(ctx), tok, f.GetContent(ctx))
|
||||||
return f, m, nil
|
return f, m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getGoFile(ctx context.Context, v source.View, uri span.URI) (source.GoFile, *protocol.ColumnMapper, error) {
|
||||||
|
f, m, err := getSourceFile(ctx, v, uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
gof, ok := f.(source.GoFile)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("not a go file %v", f.URI())
|
||||||
|
}
|
||||||
|
return gof, m, nil
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user