mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
internal/lsp: distinguish parse errors from actual errors
Parse errors need to be treated separately from actual errors when parsing a file. Parse errors are treated more like values, whereas actual errors should not be propagated to the user. This enables us to delete some of the special handling for context.Canceled errors. Change-Id: I93a02f22b3f54beccbd6bcf26f04bb8da0202c25 Reviewed-on: https://go-review.googlesource.com/c/tools/+/195997 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
d997db1b28
commit
1cc9451822
4
internal/lsp/cache/builtin.go
vendored
4
internal/lsp/cache/builtin.go
vendored
@ -43,8 +43,8 @@ func (view *view) buildBuiltinPackage(ctx context.Context) error {
|
|||||||
fh := view.session.GetFile(span.FileURI(filename))
|
fh := view.session.GetFile(span.FileURI(filename))
|
||||||
ph := view.session.cache.ParseGoHandle(fh, source.ParseFull)
|
ph := view.session.cache.ParseGoHandle(fh, source.ParseFull)
|
||||||
view.builtin.files = append(view.builtin.files, ph)
|
view.builtin.files = append(view.builtin.files, ph)
|
||||||
file, _, err := ph.Parse(ctx)
|
file, _, _, err := ph.Parse(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
files[filename] = file
|
files[filename] = file
|
||||||
|
11
internal/lsp/cache/check.go
vendored
11
internal/lsp/cache/check.go
vendored
@ -258,15 +258,12 @@ func (imp *importer) typeCheck(ctx context.Context, cph *checkPackageHandle, m *
|
|||||||
go func(i int, ph source.ParseGoHandle) {
|
go func(i int, ph source.ParseGoHandle) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
files[i], _, parseErrors[i] = ph.Parse(ctx)
|
files[i], _, parseErrors[i], _ = ph.Parse(ctx)
|
||||||
}(i, ph)
|
}(i, ph)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
for _, err := range parseErrors {
|
for _, err := range parseErrors {
|
||||||
if err == context.Canceled {
|
|
||||||
return nil, errors.Errorf("parsing files for %s: %v", m.pkgPath, err)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
imp.view.session.cache.appendPkgError(pkg, err)
|
imp.view.session.cache.appendPkgError(pkg, err)
|
||||||
}
|
}
|
||||||
@ -350,9 +347,9 @@ func (imp *importer) cachePerFile(ctx context.Context, gof *goFile, ph source.Pa
|
|||||||
}
|
}
|
||||||
gof.cphs[cph.m.id] = cph
|
gof.cphs[cph.m.id] = cph
|
||||||
|
|
||||||
file, _, err := ph.Parse(ctx)
|
file, _, _, err := ph.Parse(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return errors.Errorf("no AST for %s: %v", ph.File().Identity().URI, err)
|
return err
|
||||||
}
|
}
|
||||||
gof.imports = file.Imports
|
gof.imports = file.Imports
|
||||||
return nil
|
return nil
|
||||||
|
42
internal/lsp/cache/load.go
vendored
42
internal/lsp/cache/load.go
vendored
@ -88,25 +88,33 @@ func (view *view) load(ctx context.Context, f *goFile, fh source.FileHandle) ([]
|
|||||||
|
|
||||||
// checkMetadata determines if we should run go/packages.Load for this file.
|
// checkMetadata determines if we should run go/packages.Load for this file.
|
||||||
// If yes, update the metadata for the file and its package.
|
// If yes, update the metadata for the file and its package.
|
||||||
func (v *view) checkMetadata(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
|
func (v *view) checkMetadata(ctx context.Context, f *goFile, fh source.FileHandle) (metadata []*metadata, err error) {
|
||||||
// Check if we need to re-run go/packages before loading the package.
|
// Check if we need to re-run go/packages before loading the package.
|
||||||
f.mu.Lock()
|
var runGopackages bool
|
||||||
runGopackages := v.shouldRunGopackages(ctx, f, fh)
|
func() {
|
||||||
metadata := f.metadata()
|
f.mu.Lock()
|
||||||
f.mu.Unlock()
|
defer f.mu.Unlock()
|
||||||
|
|
||||||
|
runGopackages, err = v.shouldRunGopackages(ctx, f, fh)
|
||||||
|
metadata = f.metadata()
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// The package metadata is correct as-is, so just return it.
|
// The package metadata is correct as-is, so just return it.
|
||||||
if !runGopackages {
|
if !runGopackages {
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the context has been canceled before calling packages.Load.
|
// Don't bother running go/packages if the context has been canceled.
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, done := trace.StartSpan(ctx, "packages.Load", telemetry.File.Of(f.filename()))
|
ctx, done := trace.StartSpan(ctx, "packages.Load", telemetry.File.Of(f.filename()))
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
pkgs, err := packages.Load(v.Config(ctx), fmt.Sprintf("file=%s", f.filename()))
|
pkgs, err := packages.Load(v.Config(ctx), fmt.Sprintf("file=%s", f.filename()))
|
||||||
if len(pkgs) == 0 {
|
if len(pkgs) == 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -185,18 +193,14 @@ func sameSet(x, y map[packagePath]struct{}) bool {
|
|||||||
// shouldRunGopackages reparses a file's package and import declarations to
|
// shouldRunGopackages reparses a file's package and import declarations to
|
||||||
// determine if they have changed.
|
// determine if they have changed.
|
||||||
// It assumes that the caller holds the lock on the f.mu lock.
|
// It assumes that the caller holds the lock on the f.mu lock.
|
||||||
func (v *view) shouldRunGopackages(ctx context.Context, f *goFile, fh source.FileHandle) (result bool) {
|
func (v *view) shouldRunGopackages(ctx context.Context, f *goFile, fh source.FileHandle) (result bool, err error) {
|
||||||
if len(f.meta) == 0 || len(f.missingImports) > 0 {
|
if len(f.meta) == 0 || len(f.missingImports) > 0 {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
// Get file content in case we don't already have it.
|
// Get file content in case we don't already have it.
|
||||||
parsed, _, err := v.session.cache.ParseGoHandle(fh, source.ParseHeader).Parse(ctx)
|
parsed, _, _, err := v.session.cache.ParseGoHandle(fh, source.ParseHeader).Parse(ctx)
|
||||||
if err == context.Canceled {
|
if err != nil {
|
||||||
log.Error(ctx, "parsing file header", err, tag.Of("file", f.URI()))
|
return false, err
|
||||||
return false
|
|
||||||
}
|
|
||||||
if parsed == nil {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
// Check if the package's name has changed, by checking if this is a filename
|
// Check if the package's name has changed, by checking if this is a filename
|
||||||
// we already know about, and if so, check if its package name has changed.
|
// we already know about, and if so, check if its package name has changed.
|
||||||
@ -204,21 +208,21 @@ func (v *view) shouldRunGopackages(ctx context.Context, f *goFile, fh source.Fil
|
|||||||
for _, uri := range m.files {
|
for _, uri := range m.files {
|
||||||
if span.CompareURI(uri, f.URI()) == 0 {
|
if span.CompareURI(uri, f.URI()) == 0 {
|
||||||
if m.name != parsed.Name.Name {
|
if m.name != parsed.Name.Name {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the package's imports have changed, re-run `go list`.
|
// If the package's imports have changed, re-run `go list`.
|
||||||
if len(f.imports) != len(parsed.Imports) {
|
if len(f.imports) != len(parsed.Imports) {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
for i, importSpec := range f.imports {
|
for i, importSpec := range f.imports {
|
||||||
if importSpec.Path.Value != parsed.Imports[i].Path.Value {
|
if importSpec.Path.Value != parsed.Imports[i].Path.Value {
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type importGraph struct {
|
type importGraph struct {
|
||||||
|
75
internal/lsp/cache/parse.go
vendored
75
internal/lsp/cache/parse.go
vendored
@ -41,9 +41,10 @@ type parseGoHandle struct {
|
|||||||
type parseGoData struct {
|
type parseGoData struct {
|
||||||
memoize.NoCopy
|
memoize.NoCopy
|
||||||
|
|
||||||
ast *ast.File
|
ast *ast.File
|
||||||
mapper *protocol.ColumnMapper
|
parseError error // errors associated with parsing the file
|
||||||
err error
|
mapper *protocol.ColumnMapper
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) source.ParseGoHandle {
|
func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) source.ParseGoHandle {
|
||||||
@ -53,18 +54,7 @@ func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc
|
|||||||
}
|
}
|
||||||
h := c.store.Bind(key, func(ctx context.Context) interface{} {
|
h := c.store.Bind(key, func(ctx context.Context) interface{} {
|
||||||
data := &parseGoData{}
|
data := &parseGoData{}
|
||||||
data.ast, data.err = parseGo(ctx, c, fh, mode)
|
data.ast, data.mapper, data.parseError, data.err = parseGo(ctx, c, fh, mode)
|
||||||
tok := c.FileSet().File(data.ast.Pos())
|
|
||||||
if tok == nil {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
uri := fh.Identity().URI
|
|
||||||
content, _, err := fh.Read(ctx)
|
|
||||||
if err != nil {
|
|
||||||
data.err = err
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
data.mapper = newColumnMapper(uri, c.FileSet(), tok, content)
|
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
return &parseGoHandle{
|
return &parseGoHandle{
|
||||||
@ -73,13 +63,6 @@ func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc
|
|||||||
mode: mode,
|
mode: mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func newColumnMapper(uri span.URI, fset *token.FileSet, tok *token.File, content []byte) *protocol.ColumnMapper {
|
|
||||||
return &protocol.ColumnMapper{
|
|
||||||
URI: uri,
|
|
||||||
Converter: span.NewTokenConverter(fset, tok),
|
|
||||||
Content: content,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *parseGoHandle) File() source.FileHandle {
|
func (h *parseGoHandle) File() source.FileHandle {
|
||||||
return h.file
|
return h.file
|
||||||
@ -89,22 +72,22 @@ func (h *parseGoHandle) Mode() source.ParseMode {
|
|||||||
return h.mode
|
return h.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *parseGoHandle) Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error) {
|
func (h *parseGoHandle) Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error) {
|
||||||
v := h.handle.Get(ctx)
|
v := h.handle.Get(ctx)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil, nil, ctx.Err()
|
return nil, nil, nil, ctx.Err()
|
||||||
}
|
}
|
||||||
data := v.(*parseGoData)
|
data := v.(*parseGoData)
|
||||||
return data.ast, data.mapper, data.err
|
return data.ast, data.mapper, data.parseError, data.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *parseGoHandle) Cached(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error) {
|
func (h *parseGoHandle) Cached(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error) {
|
||||||
v := h.handle.Cached()
|
v := h.handle.Cached()
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil, nil, errors.Errorf("no cached value for %s", h.file.Identity().URI)
|
return nil, nil, nil, errors.Errorf("no cached AST for %s", h.file.Identity().URI)
|
||||||
}
|
}
|
||||||
data := v.(*parseGoData)
|
data := v.(*parseGoData)
|
||||||
return data.ast, data.mapper, data.err
|
return data.ast, data.mapper, data.parseError, data.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashParseKey(ph source.ParseGoHandle) string {
|
func hashParseKey(ph source.ParseGoHandle) string {
|
||||||
@ -122,13 +105,13 @@ func hashParseKeys(phs []source.ParseGoHandle) string {
|
|||||||
return hashContents(b.Bytes())
|
return hashContents(b.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGo(ctx context.Context, c *cache, fh source.FileHandle, mode source.ParseMode) (*ast.File, error) {
|
func parseGo(ctx context.Context, c *cache, fh source.FileHandle, mode source.ParseMode) (file *ast.File, mapper *protocol.ColumnMapper, parseError error, err error) {
|
||||||
ctx, done := trace.StartSpan(ctx, "cache.parseGo", telemetry.File.Of(fh.Identity().URI.Filename()))
|
ctx, done := trace.StartSpan(ctx, "cache.parseGo", telemetry.File.Of(fh.Identity().URI.Filename()))
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
buf, _, err := fh.Read(ctx)
|
buf, _, err := fh.Read(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
parseLimit <- struct{}{}
|
parseLimit <- struct{}{}
|
||||||
defer func() { <-parseLimit }()
|
defer func() { <-parseLimit }()
|
||||||
@ -136,21 +119,37 @@ func parseGo(ctx context.Context, c *cache, fh source.FileHandle, mode source.Pa
|
|||||||
if mode == source.ParseHeader {
|
if mode == source.ParseHeader {
|
||||||
parserMode = parser.ImportsOnly | parser.ParseComments
|
parserMode = parser.ImportsOnly | parser.ParseComments
|
||||||
}
|
}
|
||||||
ast, err := parser.ParseFile(c.fset, fh.Identity().URI.Filename(), buf, parserMode)
|
file, parseError = parser.ParseFile(c.fset, fh.Identity().URI.Filename(), buf, parserMode)
|
||||||
if ast != nil {
|
if file != nil {
|
||||||
if mode == source.ParseExported {
|
if mode == source.ParseExported {
|
||||||
trimAST(ast)
|
trimAST(file)
|
||||||
}
|
}
|
||||||
// Fix any badly parsed parts of the AST.
|
// Fix any badly parsed parts of the AST.
|
||||||
tok := c.fset.File(ast.Pos())
|
tok := c.fset.File(file.Pos())
|
||||||
if err := fix(ctx, ast, tok, buf); err != nil {
|
if err := fix(ctx, file, tok, buf); err != nil {
|
||||||
log.Error(ctx, "failed to fix AST", err)
|
log.Error(ctx, "failed to fix AST", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ast == nil {
|
// If the file is nil only due to parse errors,
|
||||||
return nil, err
|
// the parse errors are the actual errors.
|
||||||
|
if file == nil {
|
||||||
|
return nil, nil, parseError, parseError
|
||||||
}
|
}
|
||||||
return ast, err
|
tok := c.FileSet().File(file.Pos())
|
||||||
|
if tok == nil {
|
||||||
|
return nil, nil, parseError, err
|
||||||
|
}
|
||||||
|
uri := fh.Identity().URI
|
||||||
|
content, _, err := fh.Read(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, parseError, err
|
||||||
|
}
|
||||||
|
m := &protocol.ColumnMapper{
|
||||||
|
URI: uri,
|
||||||
|
Converter: span.NewTokenConverter(c.FileSet(), tok),
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
return file, m, parseError, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// trimAST clears any part of the AST not relevant to type checking
|
// trimAST clears any part of the AST not relevant to type checking
|
||||||
|
13
internal/lsp/cache/pkg.go
vendored
13
internal/lsp/cache/pkg.go
vendored
@ -151,11 +151,20 @@ func (pkg *pkg) Files() []source.ParseGoHandle {
|
|||||||
return pkg.files
|
return pkg.files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pkg *pkg) File(uri span.URI) (source.ParseGoHandle, error) {
|
||||||
|
for _, ph := range pkg.Files() {
|
||||||
|
if ph.File().Identity().URI == uri {
|
||||||
|
return ph, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.Errorf("no ParseGoHandle for %s", uri)
|
||||||
|
}
|
||||||
|
|
||||||
func (pkg *pkg) GetSyntax(ctx context.Context) []*ast.File {
|
func (pkg *pkg) GetSyntax(ctx context.Context) []*ast.File {
|
||||||
var syntax []*ast.File
|
var syntax []*ast.File
|
||||||
for _, ph := range pkg.files {
|
for _, ph := range pkg.files {
|
||||||
file, _, _ := ph.Cached(ctx)
|
file, _, _, err := ph.Cached(ctx)
|
||||||
if file != nil {
|
if err == nil {
|
||||||
syntax = append(syntax, file)
|
syntax = append(syntax, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ func (s *Server) diagnostics(view source.View, uri span.URI) error {
|
|||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
ctx = telemetry.File.With(ctx, uri)
|
ctx = telemetry.File.With(ctx, uri)
|
||||||
|
|
||||||
f, err := view.GetFile(ctx, uri)
|
f, err := view.GetFile(ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -45,8 +46,9 @@ func (s *Server) diagnostics(view source.View, uri span.URI) error {
|
|||||||
if s.undelivered == nil {
|
if s.undelivered == nil {
|
||||||
s.undelivered = make(map[span.URI][]source.Diagnostic)
|
s.undelivered = make(map[span.URI][]source.Diagnostic)
|
||||||
}
|
}
|
||||||
log.Error(ctx, "failed to deliver diagnostic (will retry)", err, telemetry.File)
|
|
||||||
s.undelivered[uri] = diagnostics
|
s.undelivered[uri] = diagnostics
|
||||||
|
|
||||||
|
log.Error(ctx, "failed to deliver diagnostic (will retry)", err, telemetry.File)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// In case we had old, undelivered diagnostics.
|
// In case we had old, undelivered diagnostics.
|
||||||
@ -58,6 +60,7 @@ func (s *Server) diagnostics(view source.View, uri span.URI) error {
|
|||||||
if err := s.publishDiagnostics(ctx, uri, diagnostics); err != nil {
|
if err := s.publishDiagnostics(ctx, uri, diagnostics); err != nil {
|
||||||
log.Error(ctx, "failed to deliver diagnostic for (will not retry)", err, telemetry.File)
|
log.Error(ctx, "failed to deliver diagnostic for (will not retry)", err, telemetry.File)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we fail to deliver the same diagnostics twice, just give up.
|
// If we fail to deliver the same diagnostics twice, just give up.
|
||||||
delete(s.undelivered, uri)
|
delete(s.undelivered, uri)
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@ func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLink
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fh := f.Handle(ctx)
|
fh := f.Handle(ctx)
|
||||||
file, m, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
|
file, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var links []protocol.DocumentLink
|
var links []protocol.DocumentLink
|
||||||
|
@ -376,14 +376,12 @@ func Completion(ctx context.Context, view View, f GoFile, pos protocol.Position,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
var ph ParseGoHandle
|
ph, err := pkg.File(f.URI())
|
||||||
for _, h := range pkg.Files() {
|
if err != nil {
|
||||||
if h.File().Identity().URI == f.URI() {
|
return nil, nil, err
|
||||||
ph = h
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
file, m, err := ph.Cached(ctx)
|
file, m, _, err := ph.Cached(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
spn, err := m.PointSpan(pos)
|
spn, err := m.PointSpan(pos)
|
||||||
|
@ -123,14 +123,13 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
|||||||
if !pos.IsValid() {
|
if !pos.IsValid() {
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
uri := span.FileURI(pos.Filename)
|
uri := span.FileURI(pos.Filename)
|
||||||
ph, pkg, err := c.pkg.FindFile(c.ctx, uri)
|
ph, pkg, err := c.pkg.FindFile(c.ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return CompletionItem{}, err
|
return CompletionItem{}, err
|
||||||
}
|
}
|
||||||
file, _, err := ph.Cached(c.ctx)
|
file, _, _, err := ph.Cached(c.ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return CompletionItem{}, err
|
return CompletionItem{}, err
|
||||||
}
|
}
|
||||||
if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
|
if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
@ -181,22 +180,15 @@ func diagnostics(ctx context.Context, view View, pkg Package, reports map[span.U
|
|||||||
// spanToRange converts a span.Span to a protocol.Range,
|
// spanToRange converts a span.Span to a protocol.Range,
|
||||||
// assuming that the span belongs to the package whose diagnostics are being computed.
|
// assuming that the span belongs to the package whose diagnostics are being computed.
|
||||||
func spanToRange(ctx context.Context, view View, pkg Package, spn span.Span, isTypeError bool) (protocol.Range, error) {
|
func spanToRange(ctx context.Context, view View, pkg Package, spn span.Span, isTypeError bool) (protocol.Range, error) {
|
||||||
var (
|
ph, err := pkg.File(spn.URI())
|
||||||
fh FileHandle
|
if err != nil {
|
||||||
file *ast.File
|
|
||||||
m *protocol.ColumnMapper
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
for _, ph := range pkg.Files() {
|
|
||||||
if ph.File().Identity().URI == spn.URI() {
|
|
||||||
fh = ph.File()
|
|
||||||
file, m, err = ph.Cached(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if file == nil {
|
|
||||||
return protocol.Range{}, err
|
return protocol.Range{}, err
|
||||||
}
|
}
|
||||||
data, _, err := fh.Read(ctx)
|
_, m, _, err := ph.Cached(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return protocol.Range{}, err
|
||||||
|
}
|
||||||
|
data, _, err := ph.File().Read(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return protocol.Range{}, err
|
return protocol.Range{}, err
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ type FoldingRangeInfo struct {
|
|||||||
func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool) (ranges []*FoldingRangeInfo, err error) {
|
func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool) (ranges []*FoldingRangeInfo, err error) {
|
||||||
// TODO(suzmue): consider limiting the number of folding ranges returned, and
|
// TODO(suzmue): consider limiting the number of folding ranges returned, and
|
||||||
// implement a way to prioritize folding ranges in that case.
|
// implement a way to prioritize folding ranges in that case.
|
||||||
fh := f.Handle(ctx)
|
ph := view.Session().Cache().ParseGoHandle(f.Handle(ctx), ParseFull)
|
||||||
ph := view.Session().Cache().ParseGoHandle(fh, ParseFull)
|
file, m, _, err := ph.Parse(ctx)
|
||||||
file, m, err := ph.Parse(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -37,17 +37,12 @@ func Format(ctx context.Context, view View, f File) ([]protocol.TextEdit, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ph ParseGoHandle
|
ph, err := pkg.File(f.URI())
|
||||||
for _, h := range pkg.Files() {
|
if err != nil {
|
||||||
if h.File().Identity().URI == f.URI() {
|
|
||||||
ph = h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ph == nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
file, m, err := ph.Parse(ctx)
|
file, m, _, err := ph.Parse(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if hasListErrors(pkg.GetErrors()) || hasParseErrors(pkg, f.URI()) {
|
if hasListErrors(pkg.GetErrors()) || hasParseErrors(pkg, f.URI()) {
|
||||||
@ -102,13 +97,8 @@ func Imports(ctx context.Context, view View, f GoFile, rng span.Range) ([]protoc
|
|||||||
if hasListErrors(pkg.GetErrors()) {
|
if hasListErrors(pkg.GetErrors()) {
|
||||||
return nil, errors.Errorf("%s has list errors, not running goimports", f.URI())
|
return nil, errors.Errorf("%s has list errors, not running goimports", f.URI())
|
||||||
}
|
}
|
||||||
var ph ParseGoHandle
|
ph, err := pkg.File(f.URI())
|
||||||
for _, h := range pkg.Files() {
|
if err != nil {
|
||||||
if h.File().Identity().URI == f.URI() {
|
|
||||||
ph = h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ph == nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
options := &imports.Options{
|
options := &imports.Options{
|
||||||
@ -133,8 +123,8 @@ func Imports(ctx context.Context, view View, f GoFile, rng span.Range) ([]protoc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, m, err := ph.Parse(ctx)
|
_, m, _, err := ph.Parse(ctx)
|
||||||
if m == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return computeTextEdits(ctx, ph.File(), m, string(formatted))
|
return computeTextEdits(ctx, ph.File(), m, string(formatted))
|
||||||
@ -201,8 +191,8 @@ func AllImportsFixes(ctx context.Context, view View, f File) (edits []protocol.T
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, m, err := ph.Parse(ctx)
|
_, m, _, err := ph.Parse(ctx)
|
||||||
if m == nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
edits, err = computeTextEdits(ctx, ph.File(), m, string(formatted))
|
edits, err = computeTextEdits(ctx, ph.File(), m, string(formatted))
|
||||||
|
@ -23,10 +23,9 @@ func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Positi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fh := f.Handle(ctx)
|
ph := view.Session().Cache().ParseGoHandle(f.Handle(ctx), ParseFull)
|
||||||
ph := view.Session().Cache().ParseGoHandle(fh, ParseFull)
|
file, m, _, err := ph.Parse(ctx)
|
||||||
file, m, err := ph.Parse(ctx)
|
if err != nil {
|
||||||
if file == nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
spn, err := m.PointSpan(pos)
|
spn, err := m.PointSpan(pos)
|
||||||
|
@ -57,15 +57,12 @@ func Identifier(ctx context.Context, view View, f GoFile, pos protocol.Position)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ph ParseGoHandle
|
ph, err := pkg.File(f.URI())
|
||||||
for _, h := range cph.Files() {
|
if err != nil {
|
||||||
if h.File().Identity().URI == f.URI() {
|
return nil, err
|
||||||
ph = h
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
file, m, err := ph.Cached(ctx)
|
file, m, _, err := ph.Cached(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
spn, err := m.PointSpan(pos)
|
spn, err := m.PointSpan(pos)
|
||||||
@ -246,7 +243,7 @@ func objToNode(ctx context.Context, view View, pkg Package, obj types.Object) (a
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
declAST, _, err := ph.Cached(ctx)
|
declAST, _, _, err := ph.Cached(ctx)
|
||||||
if declAST == nil {
|
if declAST == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -176,16 +176,12 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
|
|||||||
// getPkgName gets the pkg name associated with an identifer representing
|
// getPkgName gets the pkg name associated with an identifer representing
|
||||||
// the import path in an import spec.
|
// the import path in an import spec.
|
||||||
func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) {
|
func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) {
|
||||||
var (
|
ph, err := i.pkg.File(i.URI())
|
||||||
file *ast.File
|
if err != nil {
|
||||||
err error
|
return nil, err
|
||||||
)
|
|
||||||
for _, ph := range i.pkg.Files() {
|
|
||||||
if ph.File().Identity().URI == i.File.File().Identity().URI {
|
|
||||||
file, _, err = ph.Cached(ctx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if file == nil {
|
file, _, _, err := ph.Cached(ctx)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var namePos token.Pos
|
var namePos token.Pos
|
||||||
@ -198,7 +194,6 @@ func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error
|
|||||||
if !namePos.IsValid() {
|
if !namePos.IsValid() {
|
||||||
return nil, errors.Errorf("import spec not found for %q", i.Name)
|
return nil, errors.Errorf("import spec not found for %q", i.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for the object defined at NamePos.
|
// Look for the object defined at NamePos.
|
||||||
for _, obj := range i.pkg.GetTypesInfo().Defs {
|
for _, obj := range i.pkg.GetTypesInfo().Defs {
|
||||||
pkgName, ok := obj.(*types.PkgName)
|
pkgName, ok := obj.(*types.PkgName)
|
||||||
|
@ -40,15 +40,12 @@ func SignatureHelp(ctx context.Context, view View, f GoFile, pos protocol.Positi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ph ParseGoHandle
|
ph, err := pkg.File(f.URI())
|
||||||
for _, h := range pkg.Files() {
|
if err != nil {
|
||||||
if h.File().Identity().URI == f.URI() {
|
return nil, err
|
||||||
ph = h
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
file, m, err := ph.Cached(ctx)
|
file, m, _, err := ph.Cached(ctx)
|
||||||
if file == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
spn, err := m.PointSpan(pos)
|
spn, err := m.PointSpan(pos)
|
||||||
|
@ -18,8 +18,8 @@ func getCodeActions(ctx context.Context, view View, pkg Package, diag analysis.D
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, m, err := ph.Cached(ctx)
|
_, m, _, err := ph.Cached(ctx)
|
||||||
if m == nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mrng, err := posToRange(ctx, view, m, e.Pos, e.End)
|
mrng, err := posToRange(ctx, view, m, e.Pos, e.End)
|
||||||
|
@ -27,16 +27,12 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
ph, err := pkg.File(f.URI())
|
||||||
file *ast.File
|
if err != nil {
|
||||||
m *protocol.ColumnMapper
|
return nil, err
|
||||||
)
|
|
||||||
for _, ph := range pkg.Files() {
|
|
||||||
if ph.File().Identity().URI == f.URI() {
|
|
||||||
file, m, err = ph.Cached(ctx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if file == nil {
|
file, m, _, err := ph.Cached(ctx)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +92,8 @@ func IsGenerated(ctx context.Context, view View, uri span.URI) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ph := view.Session().Cache().ParseGoHandle(f.Handle(ctx), ParseHeader)
|
ph := view.Session().Cache().ParseGoHandle(f.Handle(ctx), ParseHeader)
|
||||||
parsed, _, err := ph.Parse(ctx)
|
parsed, _, _, err := ph.Parse(ctx)
|
||||||
if parsed == nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
tok := view.Session().Cache().FileSet().File(parsed.Pos())
|
tok := view.Session().Cache().FileSet().File(parsed.Pos())
|
||||||
@ -175,11 +175,8 @@ func posToMapper(ctx context.Context, view View, pkg Package, pos token.Pos) (*p
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, m, err := ph.Cached(ctx)
|
_, m, _, err := ph.Cached(ctx)
|
||||||
if m == nil {
|
return m, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches cgo generated comment as well as the proposed standard:
|
// Matches cgo generated comment as well as the proposed standard:
|
||||||
|
@ -80,10 +80,10 @@ type ParseGoHandle interface {
|
|||||||
|
|
||||||
// Parse returns the parsed AST for the file.
|
// Parse returns the parsed AST for the file.
|
||||||
// If the file is not available, returns nil and an error.
|
// If the file is not available, returns nil and an error.
|
||||||
Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error)
|
Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error)
|
||||||
|
|
||||||
// Cached returns the AST for this handle, if it has already been stored.
|
// Cached returns the AST for this handle, if it has already been stored.
|
||||||
Cached(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error)
|
Cached(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseMode controls the content of the AST produced when parsing a source file.
|
// ParseMode controls the content of the AST produced when parsing a source file.
|
||||||
@ -288,6 +288,7 @@ type Package interface {
|
|||||||
ID() string
|
ID() string
|
||||||
PkgPath() string
|
PkgPath() string
|
||||||
Files() []ParseGoHandle
|
Files() []ParseGoHandle
|
||||||
|
File(uri span.URI) (ParseGoHandle, error)
|
||||||
GetSyntax(context.Context) []*ast.File
|
GetSyntax(context.Context) []*ast.File
|
||||||
GetErrors() []packages.Error
|
GetErrors() []packages.Error
|
||||||
GetTypes() *types.Package
|
GetTypes() *types.Package
|
||||||
|
Loading…
x
Reference in New Issue
Block a user