diff --git a/internal/lsp/cache/builtin.go b/internal/lsp/cache/builtin.go index e11f39e7d4..f70e4746d6 100644 --- a/internal/lsp/cache/builtin.go +++ b/internal/lsp/cache/builtin.go @@ -21,6 +21,10 @@ func (b *builtinPkg) Lookup(name string) *ast.Object { return b.pkg.Scope.Lookup(name) } +func (b *builtinPkg) Files() []source.ParseGoHandle { + return b.files +} + // buildBuiltinPkg builds the view's builtin package. // It assumes that the view is not active yet, // i.e. it has not been added to the session's list of views. diff --git a/internal/lsp/cache/pkg.go b/internal/lsp/cache/pkg.go index 757dc15f7e..8a0454f87f 100644 --- a/internal/lsp/cache/pkg.go +++ b/internal/lsp/cache/pkg.go @@ -202,7 +202,12 @@ func (pkg *pkg) GetDiagnostics() []source.Diagnostic { return diags } -func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, *ast.File, source.Package, error) { +func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, source.Package, error) { + // Special case for ignored files. + if p.view.Ignore(uri) { + return p.view.findIgnoredFile(ctx, uri) + } + queue := []*pkg{p} seen := make(map[string]bool) @@ -213,11 +218,7 @@ func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, for _, ph := range pkg.files { if ph.File().Identity().URI == uri { - file, _, err := ph.Cached(ctx) - if file == nil { - return nil, nil, nil, err - } - return ph, file, pkg, nil + return ph, pkg, nil } } for _, dep := range pkg.imports { @@ -226,5 +227,5 @@ func (p *pkg) FindFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, } } } - return nil, nil, nil, errors.Errorf("no file for %s", uri) + return nil, nil, errors.Errorf("no file for %s", uri) } diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index 6ad50c6435..899ce5bb75 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -23,6 +23,7 @@ import ( "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" + errors "golang.org/x/xerrors" ) type view struct { @@ -282,6 +283,16 @@ func (v *view) Ignore(uri span.URI) bool { return ok } +func (v *view) findIgnoredFile(ctx context.Context, uri span.URI) (source.ParseGoHandle, source.Package, error) { + // Check the builtin package. + for _, h := range v.BuiltinPackage().Files() { + if h.File().Identity().URI == uri { + return h, nil, nil + } + } + return nil, nil, errors.Errorf("no ignored file for %s", uri) +} + func (v *view) BackgroundContext() context.Context { v.mu.Lock() defer v.mu.Unlock() diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion_format.go index ab8ff9c4f7..162ca2bd76 100644 --- a/internal/lsp/source/completion_format.go +++ b/internal/lsp/source/completion_format.go @@ -125,10 +125,14 @@ func (c *completer) item(cand candidate) (CompletionItem, error) { } uri := span.FileURI(pos.Filename) - _, file, pkg, err := c.pkg.FindFile(c.ctx, uri) + ph, pkg, err := c.pkg.FindFile(c.ctx, uri) if err != nil { return CompletionItem{}, err } + file, _, err := ph.Cached(c.ctx) + if file == nil { + return CompletionItem{}, err + } if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) { return CompletionItem{}, errors.Errorf("no file for %s", obj.Name()) } diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go index 76f4319ea8..79c2fb58cc 100644 --- a/internal/lsp/source/diagnostics.go +++ b/internal/lsp/source/diagnostics.go @@ -245,10 +245,6 @@ func toDiagnostic(ctx context.Context, view View, diag analysis.Diagnostic, cate if diag.Category != "" { category += "." + category } - ca, err := getCodeActions(ctx, view, diag) - if err != nil { - return Diagnostic{}, err - } f, err := view.GetFile(ctx, spn.URI()) if err != nil { return Diagnostic{}, err @@ -263,6 +259,11 @@ func toDiagnostic(ctx context.Context, view View, diag analysis.Diagnostic, cate if err != nil { return Diagnostic{}, err } + ca, err := getCodeActions(ctx, view, pkg, diag) + if err != nil { + return Diagnostic{}, err + } + rng, err := spanToRange(ctx, view, pkg, spn, false) if err != nil { return Diagnostic{}, err diff --git a/internal/lsp/source/highlight.go b/internal/lsp/source/highlight.go index 8fce4a916d..4193831ea7 100644 --- a/internal/lsp/source/highlight.go +++ b/internal/lsp/source/highlight.go @@ -19,10 +19,16 @@ func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Positi ctx, done := trace.StartSpan(ctx, "source.Highlight") defer done() - file, _, m, err := fileToMapper(ctx, view, uri) + f, err := view.GetFile(ctx, uri) if err != nil { return nil, err } + fh := f.Handle(ctx) + ph := view.Session().Cache().ParseGoHandle(fh, ParseFull) + file, m, err := ph.Parse(ctx) + if file == nil { + return nil, err + } spn, err := m.PointSpan(pos) if err != nil { return nil, err @@ -43,7 +49,7 @@ func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Positi if id.Obj != nil { ast.Inspect(path[len(path)-1], func(n ast.Node) bool { if n, ok := n.(*ast.Ident); ok && n.Obj == id.Obj { - rng, err := nodeToProtocolRange(ctx, view, n) + rng, err := nodeToProtocolRange(ctx, view, m, n) if err == nil { result = append(result, rng) } diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go index cb37dbb3fc..7f15a99245 100644 --- a/internal/lsp/source/identifier.go +++ b/internal/lsp/source/identifier.go @@ -48,10 +48,25 @@ type Declaration struct { // Identifier returns identifier information for a position // in a file, accounting for a potentially incomplete selector. func Identifier(ctx context.Context, view View, f GoFile, pos protocol.Position) (*IdentifierInfo, error) { - file, pkgs, m, err := fileToMapper(ctx, view, f.URI()) + pkgs, err := f.GetPackages(ctx) if err != nil { return nil, err } + pkg, err := bestPackage(f.URI(), pkgs) + if err != nil { + return nil, err + } + var ph ParseGoHandle + for _, h := range pkg.GetHandles() { + if h.File().Identity().URI == f.URI() { + ph = h + break + } + } + file, m, err := ph.Cached(ctx) + if file == nil { + return nil, err + } spn, err := m.PointSpan(pos) if err != nil { return nil, err @@ -121,7 +136,7 @@ func identifier(ctx context.Context, view View, pkgs []Package, file *ast.File, } } result.Name = result.ident.Name - if result.mappedRange, err = posToRange(ctx, view, result.ident.Pos(), result.ident.End()); err != nil { + if result.mappedRange, err = posToMappedRange(ctx, view, pkg, result.ident.Pos(), result.ident.End()); err != nil { return nil, err } result.Declaration.obj = pkg.GetTypesInfo().ObjectOf(result.ident) @@ -152,7 +167,7 @@ func identifier(ctx context.Context, view View, pkgs []Package, file *ast.File, return nil, errors.Errorf("no declaration for %s", result.Name) } result.Declaration.node = decl - if result.Declaration.mappedRange, err = nameToMappedRange(ctx, view, decl.Pos(), result.Name); err != nil { + if result.Declaration.mappedRange, err = nameToMappedRange(ctx, view, pkg, decl.Pos(), result.Name); err != nil { return nil, err } return result, nil @@ -177,7 +192,7 @@ func identifier(ctx context.Context, view View, pkgs []Package, file *ast.File, } } - if result.Declaration.mappedRange, err = objToMappedRange(ctx, view, result.Declaration.obj); err != nil { + if result.Declaration.mappedRange, err = objToMappedRange(ctx, view, pkg, result.Declaration.obj); err != nil { return nil, err } if result.Declaration.node, err = objToNode(ctx, view, pkg, result.Declaration.obj); err != nil { @@ -194,7 +209,7 @@ func identifier(ctx context.Context, view View, pkgs []Package, file *ast.File, if hasErrorType(result.Type.Object) { return result, nil } - if result.Type.mappedRange, err = objToMappedRange(ctx, view, result.Type.Object); err != nil { + if result.Type.mappedRange, err = objToMappedRange(ctx, view, pkg, result.Type.Object); err != nil { return nil, err } } @@ -230,7 +245,11 @@ func hasErrorType(obj types.Object) bool { func objToNode(ctx context.Context, view View, pkg Package, obj types.Object) (ast.Decl, error) { uri := span.FileURI(view.Session().Cache().FileSet().Position(obj.Pos()).Filename) - _, declAST, _, err := pkg.FindFile(ctx, uri) + ph, _, err := pkg.FindFile(ctx, uri) + if err != nil { + return nil, err + } + declAST, _, err := ph.Cached(ctx) if declAST == nil { return nil, err } @@ -291,7 +310,7 @@ func importSpec(ctx context.Context, view View, fAST *ast.File, pkgs []Package, Name: importPath, pkgs: pkgs, } - if result.mappedRange, err = posToRange(ctx, view, imp.Path.Pos(), imp.Path.End()); err != nil { + if result.mappedRange, err = posToMappedRange(ctx, view, pkg, imp.Path.Pos(), imp.Path.End()); err != nil { return nil, err } // Consider the "declaration" of an import spec to be the imported package. @@ -312,7 +331,7 @@ func importSpec(ctx context.Context, view View, fAST *ast.File, pkgs []Package, if dest == nil { return nil, errors.Errorf("package %q has no files", importPath) } - if result.Declaration.mappedRange, err = posToRange(ctx, view, dest.Pos(), dest.End()); err != nil { + if result.Declaration.mappedRange, err = posToMappedRange(ctx, view, pkg, dest.Pos(), dest.End()); err != nil { return nil, err } result.Declaration.node = imp diff --git a/internal/lsp/source/references.go b/internal/lsp/source/references.go index 142c3c0789..1d1a993ee4 100644 --- a/internal/lsp/source/references.go +++ b/internal/lsp/source/references.go @@ -56,7 +56,7 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro if obj == nil || !sameObj(obj, i.Declaration.obj) { continue } - rng, err := posToRange(ctx, i.View, ident.Pos(), ident.End()) + rng, err := posToMappedRange(ctx, i.View, pkg, ident.Pos(), ident.End()) if err != nil { return nil, err } @@ -74,7 +74,7 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro if obj == nil || !sameObj(obj, i.Declaration.obj) { continue } - rng, err := posToRange(ctx, i.View, ident.Pos(), ident.End()) + rng, err := posToMappedRange(ctx, i.View, pkg, ident.Pos(), ident.End()) if err != nil { return nil, err } diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go index 6ba33314f4..6f145479b4 100644 --- a/internal/lsp/source/rename.go +++ b/internal/lsp/source/rename.go @@ -149,13 +149,25 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string) } result := make(map[span.URI][]protocol.TextEdit) for uri, edits := range changes { - // Sort the edits first. - diff.SortTextEdits(edits) - - _, m, err := cachedFileToMapper(ctx, view, uri) + // These edits should really be associated with FileHandles for maximal correctness. + // For now, this is good enough. + f, err := view.GetFile(ctx, uri) if err != nil { return nil, err } + fh := f.Handle(ctx) + data, _, err := fh.Read(ctx) + if err != nil { + return nil, err + } + converter := span.NewContentConverter(uri.Filename(), data) + m := &protocol.ColumnMapper{ + URI: uri, + Converter: converter, + Content: data, + } + // Sort the edits first. + diff.SortTextEdits(edits) protocolEdits, err := ToProtocolEdits(m, edits) if err != nil { return nil, err @@ -218,14 +230,13 @@ func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *t obj: pkgName, wasImplicit: true, } - var err error - if decl.mappedRange, err = objToMappedRange(ctx, ident.View, decl.obj); err != nil { - return nil, err - } pkg, err := bestPackage(ident.File.File().Identity().URI, ident.pkgs) if err != nil { return nil, err } + if decl.mappedRange, err = objToMappedRange(ctx, ident.View, pkg, decl.obj); err != nil { + return nil, err + } if decl.node, err = objToNode(ctx, ident.View, pkg, decl.obj); err != nil { return nil, err } diff --git a/internal/lsp/source/signature_help.go b/internal/lsp/source/signature_help.go index cc036ca323..6260e50c51 100644 --- a/internal/lsp/source/signature_help.go +++ b/internal/lsp/source/signature_help.go @@ -31,7 +31,7 @@ func SignatureHelp(ctx context.Context, view View, f GoFile, pos protocol.Positi ctx, done := trace.StartSpan(ctx, "source.SignatureHelp") defer done() - file, pkgs, m, err := fileToMapper(ctx, view, f.URI()) + pkgs, err := f.GetPackages(ctx) if err != nil { return nil, err } @@ -39,6 +39,17 @@ func SignatureHelp(ctx context.Context, view View, f GoFile, pos protocol.Positi if err != nil { return nil, err } + var ph ParseGoHandle + for _, h := range pkg.GetHandles() { + if h.File().Identity().URI == f.URI() { + ph = h + break + } + } + file, m, err := ph.Cached(ctx) + if file == nil { + return nil, err + } spn, err := m.PointSpan(pos) if err != nil { return nil, err @@ -113,7 +124,7 @@ FindCall: if err != nil { return nil, err } - rng, err := objToMappedRange(ctx, view, obj) + rng, err := objToMappedRange(ctx, view, pkg, obj) if err != nil { return nil, err } diff --git a/internal/lsp/source/suggested_fix.go b/internal/lsp/source/suggested_fix.go index a9706103a8..d32d47de83 100644 --- a/internal/lsp/source/suggested_fix.go +++ b/internal/lsp/source/suggested_fix.go @@ -5,14 +5,24 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/internal/lsp/protocol" + "golang.org/x/tools/internal/span" ) -func getCodeActions(ctx context.Context, view View, diag analysis.Diagnostic) ([]SuggestedFix, error) { +func getCodeActions(ctx context.Context, view View, pkg Package, diag analysis.Diagnostic) ([]SuggestedFix, error) { var fixes []SuggestedFix for _, fix := range diag.SuggestedFixes { var edits []protocol.TextEdit for _, e := range fix.TextEdits { - mrng, err := posToRange(ctx, view, e.Pos, e.End) + posn := view.Session().Cache().FileSet().Position(e.Pos) + ph, _, err := pkg.FindFile(ctx, span.FileURI(posn.Filename)) + if err != nil { + return nil, err + } + _, m, err := ph.Cached(ctx) + if m == nil { + return nil, err + } + mrng, err := posToRange(ctx, view, m, e.Pos, e.End) if err != nil { return nil, err } diff --git a/internal/lsp/source/symbols.go b/internal/lsp/source/symbols.go index 1360ea1b30..42bfaa396c 100644 --- a/internal/lsp/source/symbols.go +++ b/internal/lsp/source/symbols.go @@ -22,10 +22,13 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum if err != nil { return nil, err } - var file *ast.File + var ( + file *ast.File + m *protocol.ColumnMapper + ) for _, ph := range pkg.GetHandles() { if ph.File().Identity().URI == f.URI() { - file, _, err = ph.Cached(ctx) + file, m, err = ph.Cached(ctx) } } if file == nil { @@ -42,7 +45,7 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum switch decl := decl.(type) { case *ast.FuncDecl: if obj := info.ObjectOf(decl.Name); obj != nil { - if fs := funcSymbol(ctx, view, decl, obj, q); fs.Kind == protocol.Method { + if fs := funcSymbol(ctx, view, m, decl, obj, q); fs.Kind == protocol.Method { // Store methods separately, as we want them to appear as children // of the corresponding type (which we may not have seen yet). rtype := obj.Type().(*types.Signature).Recv().Type() @@ -56,14 +59,14 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum switch spec := spec.(type) { case *ast.TypeSpec: if obj := info.ObjectOf(spec.Name); obj != nil { - ts := typeSymbol(ctx, view, info, spec, obj, q) + ts := typeSymbol(ctx, view, m, info, spec, obj, q) symbols = append(symbols, ts) symbolsToReceiver[obj.Type()] = len(symbols) - 1 } case *ast.ValueSpec: for _, name := range spec.Names { if obj := info.ObjectOf(name); obj != nil { - symbols = append(symbols, varSymbol(ctx, view, decl, name, obj, q)) + symbols = append(symbols, varSymbol(ctx, view, m, decl, name, obj, q)) } } } @@ -87,15 +90,15 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum return symbols, nil } -func funcSymbol(ctx context.Context, view View, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { +func funcSymbol(ctx context.Context, view View, m *protocol.ColumnMapper, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { s := protocol.DocumentSymbol{ Name: obj.Name(), Kind: protocol.Function, } - if span, err := nodeToProtocolRange(ctx, view, decl); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, decl); err == nil { s.Range = span } - if span, err := nodeToProtocolRange(ctx, view, decl.Name); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, decl.Name); err == nil { s.SelectionRange = span } sig, _ := obj.Type().(*types.Signature) @@ -148,17 +151,17 @@ func setKind(s *protocol.DocumentSymbol, typ types.Type, q types.Qualifier) { } } -func typeSymbol(ctx context.Context, view View, info *types.Info, spec *ast.TypeSpec, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { +func typeSymbol(ctx context.Context, view View, m *protocol.ColumnMapper, info *types.Info, spec *ast.TypeSpec, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { s := protocol.DocumentSymbol{ Name: obj.Name(), } s.Detail, _ = formatType(obj.Type(), q) setKind(&s, obj.Type(), q) - if span, err := nodeToProtocolRange(ctx, view, spec); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, spec); err == nil { s.Range = span } - if span, err := nodeToProtocolRange(ctx, view, spec.Name); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, spec.Name); err == nil { s.SelectionRange = span } t, objIsStruct := obj.Type().Underlying().(*types.Struct) @@ -173,10 +176,10 @@ func typeSymbol(ctx context.Context, view View, info *types.Info, spec *ast.Type child.Detail, _ = formatType(f.Type(), q) spanNode, selectionNode := nodesForStructField(i, st) - if span, err := nodeToProtocolRange(ctx, view, spanNode); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, spanNode); err == nil { child.Range = span } - if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, selectionNode); err == nil { child.SelectionRange = span } s.Children = append(s.Children, child) @@ -203,10 +206,10 @@ func typeSymbol(ctx context.Context, view View, info *types.Info, spec *ast.Type } } } - if span, err := nodeToProtocolRange(ctx, view, spanNode); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, spanNode); err == nil { child.Range = span } - if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, selectionNode); err == nil { child.SelectionRange = span } s.Children = append(s.Children, child) @@ -235,10 +238,10 @@ func typeSymbol(ctx context.Context, view View, info *types.Info, spec *ast.Type break Embeddeds } } - if rng, err := nodeToProtocolRange(ctx, view, spanNode); err == nil { + if rng, err := nodeToProtocolRange(ctx, view, m, spanNode); err == nil { child.Range = rng } - if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, selectionNode); err == nil { child.SelectionRange = span } s.Children = append(s.Children, child) @@ -267,7 +270,7 @@ func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) { return nil, nil } -func varSymbol(ctx context.Context, view View, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { +func varSymbol(ctx context.Context, view View, m *protocol.ColumnMapper, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) protocol.DocumentSymbol { s := protocol.DocumentSymbol{ Name: obj.Name(), Kind: protocol.Variable, @@ -275,10 +278,10 @@ func varSymbol(ctx context.Context, view View, decl ast.Node, name *ast.Ident, o if _, ok := obj.(*types.Const); ok { s.Kind = protocol.Constant } - if rng, err := nodeToProtocolRange(ctx, view, decl); err == nil { + if rng, err := nodeToProtocolRange(ctx, view, m, decl); err == nil { s.Range = rng } - if span, err := nodeToProtocolRange(ctx, view, name); err == nil { + if span, err := nodeToProtocolRange(ctx, view, m, name); err == nil { s.SelectionRange = span } s.Detail = types.TypeString(obj.Type(), q) diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go index 2ab10190a8..c992be0e07 100644 --- a/internal/lsp/source/util.go +++ b/internal/lsp/source/util.go @@ -69,73 +69,6 @@ func bestPackage(uri span.URI, pkgs []Package) (Package, error) { return result, nil } -func fileToMapper(ctx context.Context, view View, uri span.URI) (*ast.File, []Package, *protocol.ColumnMapper, error) { - f, err := view.GetFile(ctx, uri) - if err != nil { - return nil, nil, nil, err - } - gof, ok := f.(GoFile) - if !ok { - return nil, nil, nil, errors.Errorf("%s is not a Go file", f.URI()) - } - pkgs, err := gof.GetPackages(ctx) - if err != nil { - return nil, nil, nil, err - } - pkg, err := bestPackage(f.URI(), pkgs) - if err != nil { - return nil, nil, nil, err - } - file, m, err := pkgToMapper(ctx, view, pkg, f.URI()) - if err != nil { - return nil, nil, nil, err - } - return file, pkgs, m, nil -} - -func cachedFileToMapper(ctx context.Context, view View, uri span.URI) (*ast.File, *protocol.ColumnMapper, error) { - f, err := view.GetFile(ctx, uri) - if err != nil { - return nil, nil, err - } - gof, ok := f.(GoFile) - if !ok { - return nil, nil, errors.Errorf("%s is not a Go file", f.URI()) - } - pkg, err := gof.GetCachedPackage(ctx) - if err == nil { - file, m, err := pkgToMapper(ctx, view, pkg, f.URI()) - if err != nil { - return nil, nil, err - } - return file, m, nil - } - // Fallback to just looking for the AST. - ph := view.Session().Cache().ParseGoHandle(gof.Handle(ctx), ParseFull) - file, m, err := ph.Cached(ctx) - if file == nil { - return nil, nil, err - } - return file, m, nil -} - -func pkgToMapper(ctx context.Context, view View, pkg Package, uri span.URI) (*ast.File, *protocol.ColumnMapper, error) { - var ph ParseGoHandle - for _, h := range pkg.GetHandles() { - if h.File().Identity().URI == uri { - ph = h - } - } - if ph == nil { - return nil, nil, errors.Errorf("no ParseGoHandle for %s", uri) - } - file, m, err := ph.Cached(ctx) - if file == nil { - return nil, nil, err - } - return file, m, nil -} - func IsGenerated(ctx context.Context, view View, uri span.URI) bool { f, err := view.GetFile(ctx, uri) if err != nil { @@ -163,15 +96,15 @@ func IsGenerated(ctx context.Context, view View, uri span.URI) bool { return false } -func nodeToProtocolRange(ctx context.Context, view View, n ast.Node) (protocol.Range, error) { - mrng, err := nodeToMappedRange(ctx, view, n) +func nodeToProtocolRange(ctx context.Context, view View, m *protocol.ColumnMapper, n ast.Node) (protocol.Range, error) { + mrng, err := nodeToMappedRange(ctx, view, m, n) if err != nil { return protocol.Range{}, err } return mrng.Range() } -func objToMappedRange(ctx context.Context, view View, obj types.Object) (mappedRange, error) { +func objToMappedRange(ctx context.Context, view View, pkg Package, obj types.Object) (mappedRange, error) { if pkgName, ok := obj.(*types.PkgName); ok { // An imported Go package has a package-local, unqualified name. // When the name matches the imported package name, there is no @@ -184,38 +117,54 @@ func objToMappedRange(ctx context.Context, view View, obj types.Object) (mappedR // When the identifier does not appear in the source, have the range // of the object be the point at the beginning of the declaration. if pkgName.Imported().Name() == pkgName.Name() { - return nameToMappedRange(ctx, view, obj.Pos(), "") + return nameToMappedRange(ctx, view, pkg, obj.Pos(), "") } } - return nameToMappedRange(ctx, view, obj.Pos(), obj.Name()) + return nameToMappedRange(ctx, view, pkg, obj.Pos(), obj.Name()) } -func nameToMappedRange(ctx context.Context, view View, pos token.Pos, name string) (mappedRange, error) { - return posToRange(ctx, view, pos, pos+token.Pos(len(name))) +func nameToMappedRange(ctx context.Context, view View, pkg Package, pos token.Pos, name string) (mappedRange, error) { + return posToMappedRange(ctx, view, pkg, pos, pos+token.Pos(len(name))) } -func nodeToMappedRange(ctx context.Context, view View, n ast.Node) (mappedRange, error) { - return posToRange(ctx, view, n.Pos(), n.End()) +func nodeToMappedRange(ctx context.Context, view View, m *protocol.ColumnMapper, n ast.Node) (mappedRange, error) { + return posToRange(ctx, view, m, n.Pos(), n.End()) } -func posToRange(ctx context.Context, view View, pos, end token.Pos) (mappedRange, error) { +func posToMappedRange(ctx context.Context, view View, pkg Package, pos, end token.Pos) (mappedRange, error) { + m, err := posToMapper(ctx, view, pkg, pos) + if err != nil { + return mappedRange{}, err + } + return posToRange(ctx, view, m, pos, end) +} + +func posToRange(ctx context.Context, view View, m *protocol.ColumnMapper, pos, end token.Pos) (mappedRange, error) { if !pos.IsValid() { return mappedRange{}, errors.Errorf("invalid position for %v", pos) } if !end.IsValid() { return mappedRange{}, errors.Errorf("invalid position for %v", end) } - posn := view.Session().Cache().FileSet().Position(pos) - _, m, err := cachedFileToMapper(ctx, view, span.FileURI(posn.Filename)) - if err != nil { - return mappedRange{}, err - } return mappedRange{ m: m, spanRange: span.NewRange(view.Session().Cache().FileSet(), pos, end), }, nil } +func posToMapper(ctx context.Context, view View, pkg Package, pos token.Pos) (*protocol.ColumnMapper, error) { + posn := view.Session().Cache().FileSet().Position(pos) + ph, _, err := pkg.FindFile(ctx, span.FileURI(posn.Filename)) + if err != nil { + return nil, err + } + _, m, err := ph.Cached(ctx) + if m == nil { + return nil, err + } + return m, nil +} + // Matches cgo generated comment as well as the proposed standard: // https://golang.org/s/generatedcode var generatedRx = regexp.MustCompile(`// .*DO NOT EDIT\.?`) diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go index a8cd61ec65..6920312cad 100644 --- a/internal/lsp/source/view.go +++ b/internal/lsp/source/view.go @@ -319,9 +319,10 @@ type Package interface { // FindFile returns the AST and type information for a file that may // belong to or be part of a dependency of the given package. - FindFile(ctx context.Context, uri span.URI) (ParseGoHandle, *ast.File, Package, error) + FindFile(ctx context.Context, uri span.URI) (ParseGoHandle, Package, error) } type BuiltinPackage interface { Lookup(name string) *ast.Object + Files() []ParseGoHandle }