From 3beecff0f65ddefa5442beabf188a6c8411dcf82 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 10 Oct 2022 22:49:16 -0400 Subject: [PATCH] gopls/internal/span: some cleanups This change eliminates these redundant helper functions - cache.rangeFromPositions - source.LineToRange - source.ByteOffsetsToRange and makes various other simplifications and documentation improvements. Change-Id: Ic820ab560d71b88bde00b005e3a919334a5d1856 Reviewed-on: https://go-review.googlesource.com/c/tools/+/442015 TryBot-Result: Gopher Robot gopls-CI: kokoro Run-TryBot: Alan Donovan Reviewed-by: Robert Findley --- gopls/internal/lsp/cache/check.go | 2 +- gopls/internal/lsp/cache/load.go | 4 +- gopls/internal/lsp/cache/mod.go | 4 +- gopls/internal/lsp/cache/mod_tidy.go | 24 ++------ gopls/internal/lsp/diagnostics.go | 6 +- gopls/internal/lsp/lsp_test.go | 24 +++----- gopls/internal/lsp/mod/code_lens.go | 4 +- gopls/internal/lsp/mod/diagnostics.go | 4 +- gopls/internal/lsp/mod/hover.go | 4 +- gopls/internal/lsp/protocol/span.go | 65 +++++++++++++++++----- gopls/internal/lsp/source/fix.go | 12 ++-- gopls/internal/lsp/source/util.go | 24 +------- gopls/internal/lsp/text_synchronization.go | 6 +- gopls/internal/lsp/work/diagnostics.go | 2 +- gopls/internal/lsp/work/hover.go | 4 +- gopls/internal/span/span.go | 3 +- gopls/internal/span/utf16.go | 3 + 17 files changed, 95 insertions(+), 100 deletions(-) diff --git a/gopls/internal/lsp/cache/check.go b/gopls/internal/lsp/cache/check.go index 0b37135fc0..a186a81685 100644 --- a/gopls/internal/lsp/cache/check.go +++ b/gopls/internal/lsp/cache/check.go @@ -729,7 +729,7 @@ func (s *snapshot) depsErrors(ctx context.Context, pkg *pkg) ([]*source.Diagnost if reference == nil { continue } - rng, err := rangeFromPositions(pm.Mapper, reference.Start, reference.End) + rng, err := pm.Mapper.OffsetRange(reference.Start.Byte, reference.End.Byte) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/cache/load.go b/gopls/internal/lsp/cache/load.go index 3ef5301f83..c33561fe2b 100644 --- a/gopls/internal/lsp/cache/load.go +++ b/gopls/internal/lsp/cache/load.go @@ -392,8 +392,8 @@ func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, fi } case source.Mod: if pmf, err := s.ParseMod(ctx, fh); err == nil { - if pmf.File.Module != nil && pmf.File.Module.Syntax != nil { - rng, _ = rangeFromPositions(pmf.Mapper, pmf.File.Module.Syntax.Start, pmf.File.Module.Syntax.End) + if mod := pmf.File.Module; mod != nil && mod.Syntax != nil { + rng, _ = pmf.Mapper.OffsetRange(mod.Syntax.Start.Byte, mod.Syntax.End.Byte) } } } diff --git a/gopls/internal/lsp/cache/mod.go b/gopls/internal/lsp/cache/mod.go index f8404e7a9e..97bdb2f019 100644 --- a/gopls/internal/lsp/cache/mod.go +++ b/gopls/internal/lsp/cache/mod.go @@ -79,7 +79,7 @@ func parseModImpl(ctx context.Context, fh source.FileHandle) (*source.ParsedModu return nil, fmt.Errorf("unexpected parse error type %v", parseErr) } for _, mfErr := range mfErrList { - rng, err := rangeFromPositions(m, mfErr.Pos, mfErr.Pos) + rng, err := m.OffsetRange(mfErr.Pos.Byte, mfErr.Pos.Byte) if err != nil { return nil, err } @@ -155,7 +155,7 @@ func parseWorkImpl(ctx context.Context, fh source.FileHandle) (*source.ParsedWor return nil, fmt.Errorf("unexpected parse error type %v", parseErr) } for _, mfErr := range mfErrList { - rng, err := rangeFromPositions(m, mfErr.Pos, mfErr.Pos) + rng, err := m.OffsetRange(mfErr.Pos.Byte, mfErr.Pos.Byte) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/cache/mod_tidy.go b/gopls/internal/lsp/cache/mod_tidy.go index 63346dc548..8e4e060904 100644 --- a/gopls/internal/lsp/cache/mod_tidy.go +++ b/gopls/internal/lsp/cache/mod_tidy.go @@ -287,7 +287,7 @@ func modTidyDiagnostics(ctx context.Context, snapshot *snapshot, pm *source.Pars // unusedDiagnostic returns a source.Diagnostic for an unused require. func unusedDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, onlyDiagnostic bool) (*source.Diagnostic, error) { - rng, err := rangeFromPositions(m, req.Syntax.Start, req.Syntax.End) + rng, err := m.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) if err != nil { return nil, err } @@ -313,7 +313,7 @@ func unusedDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, onlyDiagno // directnessDiagnostic extracts errors when a dependency is labeled indirect when // it should be direct and vice versa. func directnessDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, computeEdits source.DiffFunction) (*source.Diagnostic, error) { - rng, err := rangeFromPositions(m, req.Syntax.Start, req.Syntax.End) + rng, err := m.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) if err != nil { return nil, err } @@ -325,8 +325,8 @@ func directnessDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, comput if comments := req.Syntax.Comment(); comments != nil && len(comments.Suffix) > 0 { end := comments.Suffix[0].Start end.LineRune += len(comments.Suffix[0].Token) - end.Byte += len([]byte(comments.Suffix[0].Token)) - rng, err = rangeFromPositions(m, comments.Suffix[0].Start, end) + end.Byte += len(comments.Suffix[0].Token) + rng, err = m.OffsetRange(comments.Suffix[0].Start.Byte, end.Byte) if err != nil { return nil, err } @@ -359,7 +359,7 @@ func missingModuleDiagnostic(pm *source.ParsedModule, req *modfile.Require) (*so if pm.File != nil && pm.File.Module != nil && pm.File.Module.Syntax != nil { start, end := pm.File.Module.Syntax.Span() var err error - rng, err = rangeFromPositions(pm.Mapper, start, end) + rng, err = pm.Mapper.OffsetRange(start.Byte, end.Byte) if err != nil { return nil, err } @@ -429,11 +429,7 @@ func missingModuleForImport(file *token.File, m *protocol.ColumnMapper, imp *ast if req.Syntax == nil { return nil, fmt.Errorf("no syntax for %v", req) } - spn, err := span.NewRange(file, imp.Path.Pos(), imp.Path.End()).Span() - if err != nil { - return nil, err - } - rng, err := m.Range(spn) + rng, err := m.PosRange(imp.Path.Pos(), imp.Path.End()) if err != nil { return nil, err } @@ -447,14 +443,6 @@ func missingModuleForImport(file *token.File, m *protocol.ColumnMapper, imp *ast }, nil } -func rangeFromPositions(m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) { - spn, err := spanFromPositions(m, s, e) - if err != nil { - return protocol.Range{}, err - } - return m.Range(spn) -} - func spanFromPositions(m *protocol.ColumnMapper, s, e modfile.Position) (span.Span, error) { toPoint := func(offset int) (span.Point, error) { l, c, err := span.ToPosition(m.TokFile, offset) diff --git a/gopls/internal/lsp/diagnostics.go b/gopls/internal/lsp/diagnostics.go index f6f9f7935a..5a47626b6e 100644 --- a/gopls/internal/lsp/diagnostics.go +++ b/gopls/internal/lsp/diagnostics.go @@ -545,11 +545,7 @@ func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snaps if !pgf.File.Name.Pos().IsValid() { return nil } - spn, err := span.NewRange(pgf.Tok, pgf.File.Name.Pos(), pgf.File.Name.End()).Span() - if err != nil { - return nil - } - rng, err := pgf.Mapper.Range(spn) + rng, err := pgf.Mapper.PosRange(pgf.File.Name.Pos(), pgf.File.Name.End()) if err != nil { return nil } diff --git a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go index 3969e88216..d966d94397 100644 --- a/gopls/internal/lsp/lsp_test.go +++ b/gopls/internal/lsp/lsp_test.go @@ -360,26 +360,18 @@ func foldRanges(m *protocol.ColumnMapper, contents string, ranges []protocol.Fol res := contents // Apply the edits from the end of the file forward // to preserve the offsets + // TODO(adonovan): factor to use diff.ApplyEdits, which validates the input. for i := len(ranges) - 1; i >= 0; i-- { - fRange := ranges[i] - spn, err := m.RangeSpan(protocol.Range{ - Start: protocol.Position{ - Line: fRange.StartLine, - Character: fRange.StartCharacter, - }, - End: protocol.Position{ - Line: fRange.EndLine, - Character: fRange.EndCharacter, - }, - }) + r := ranges[i] + start, err := m.Point(protocol.Position{r.StartLine, r.StartCharacter}) if err != nil { return "", err } - start := spn.Start().Offset() - end := spn.End().Offset() - - tmp := res[0:start] + foldedText - res = tmp + res[end:] + end, err := m.Point(protocol.Position{r.EndLine, r.EndCharacter}) + if err != nil { + return "", err + } + res = res[:start.Offset()] + foldedText + res[end.Offset():] } return res, nil } diff --git a/gopls/internal/lsp/mod/code_lens.go b/gopls/internal/lsp/mod/code_lens.go index daafee0cb5..01d75d92a2 100644 --- a/gopls/internal/lsp/mod/code_lens.go +++ b/gopls/internal/lsp/mod/code_lens.go @@ -134,7 +134,7 @@ func moduleStmtRange(fh source.FileHandle, pm *source.ParsedModule) (protocol.Ra return protocol.Range{}, fmt.Errorf("no module statement in %s", fh.URI()) } syntax := pm.File.Module.Syntax - return source.LineToRange(pm.Mapper, fh.URI(), syntax.Start, syntax.End) + return pm.Mapper.OffsetRange(syntax.Start.Byte, syntax.End.Byte) } // firstRequireRange returns the range for the first "require" in the given @@ -155,7 +155,7 @@ func firstRequireRange(fh source.FileHandle, pm *source.ParsedModule) (protocol. if start.Byte == 0 || firstRequire.Start.Byte < start.Byte { start, end = firstRequire.Start, firstRequire.End } - return source.LineToRange(pm.Mapper, fh.URI(), start, end) + return pm.Mapper.OffsetRange(start.Byte, end.Byte) } func vulncheckLenses(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { diff --git a/gopls/internal/lsp/mod/diagnostics.go b/gopls/internal/lsp/mod/diagnostics.go index d79442468c..4b4f421ece 100644 --- a/gopls/internal/lsp/mod/diagnostics.go +++ b/gopls/internal/lsp/mod/diagnostics.go @@ -136,7 +136,7 @@ func ModUpgradeDiagnostics(ctx context.Context, snapshot source.Snapshot, fh sou if !ok || req.Mod.Version == ver { continue } - rng, err := source.LineToRange(pm.Mapper, fh.URI(), req.Syntax.Start, req.Syntax.End) + rng, err := pm.Mapper.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) if err != nil { return nil, err } @@ -205,7 +205,7 @@ func ModVulnerabilityDiagnostics(ctx context.Context, snapshot source.Snapshot, if !ok { continue } - rng, err := source.LineToRange(pm.Mapper, fh.URI(), req.Syntax.Start, req.Syntax.End) + rng, err := pm.Mapper.OffsetRange(req.Syntax.Start.Byte, req.Syntax.End.Byte) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/mod/hover.go b/gopls/internal/lsp/mod/hover.go index 0f3dfc478d..29812749df 100644 --- a/gopls/internal/lsp/mod/hover.go +++ b/gopls/internal/lsp/mod/hover.go @@ -11,9 +11,9 @@ import ( "strings" "golang.org/x/mod/modfile" - "golang.org/x/tools/internal/event" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/gopls/internal/lsp/source" + "golang.org/x/tools/internal/event" ) func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.Hover, error) { @@ -78,7 +78,7 @@ func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, } // Get the range to highlight for the hover. - rng, err := source.ByteOffsetsToRange(pm.Mapper, fh.URI(), startPos, endPos) + rng, err := pm.Mapper.OffsetRange(startPos, endPos) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/protocol/span.go b/gopls/internal/lsp/protocol/span.go index bfa2f8111e..2d87c08127 100644 --- a/gopls/internal/lsp/protocol/span.go +++ b/gopls/internal/lsp/protocol/span.go @@ -4,6 +4,34 @@ // this file contains protocol<->span converters +// Here's a handy guide for your tour of the location zoo: +// +// Imports: source --> lsppos --> protocol --> span --> token +// +// source.MappedRange = (span.Range, protocol.ColumnMapper) +// +// lsppos.TokenMapper = (token.File, lsppos.Mapper) +// lsppos.Mapper = (line offset table, content) +// +// protocol.ColumnMapper = (URI, token.File, content) +// protocol.Location = (URI, protocol.Range) +// protocol.Range = (start, end Position) +// protocol.Position = (line, char uint32) 0-based UTF-16 +// +// span.Point = (line?, col?, offset?) 1-based UTF-8 +// span.Span = (uri URI, start, end span.Point) +// span.Range = (file token.File, start, end token.Pos) +// +// token.Pos +// token.FileSet +// offset int +// +// TODO(adonovan): simplify this picture. Eliminate the optionality of +// span.{Span,Point}'s position and offset fields: work internally in +// terms of offsets (like span.Range), and require a mapper to convert +// them to protocol (UTF-16) line/col form. Stop honoring //line +// directives. + package protocol import ( @@ -12,6 +40,7 @@ import ( "go/token" "unicode/utf8" + "golang.org/x/tools/gopls/internal/lsp/safetoken" "golang.org/x/tools/gopls/internal/span" ) @@ -67,7 +96,7 @@ func (m *ColumnMapper) Range(s span.Span) (Range, error) { if span.CompareURI(m.URI, s.URI()) != 0 { return Range{}, fmt.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI()) } - s, err := s.WithAll(m.TokFile) + s, err := s.WithOffset(m.TokFile) if err != nil { return Range{}, err } @@ -97,6 +126,19 @@ func (m *ColumnMapper) OffsetRange(start, end int) (Range, error) { return Range{Start: startPosition, End: endPosition}, nil } +// PosRange returns a protocol Range for the token.Pos interval Content[start:end]. +func (m *ColumnMapper) PosRange(start, end token.Pos) (Range, error) { + startOffset, err := safetoken.Offset(m.TokFile, start) + if err != nil { + return Range{}, fmt.Errorf("start: %v", err) + } + endOffset, err := safetoken.Offset(m.TokFile, end) + if err != nil { + return Range{}, fmt.Errorf("end: %v", err) + } + return m.OffsetRange(startOffset, endOffset) +} + // Position returns the protocol position for the specified point, // which must have a byte offset. func (m *ColumnMapper) Position(p span.Point) (Position, error) { @@ -163,6 +205,8 @@ func (m *ColumnMapper) Span(l Location) (span.Span, error) { return m.RangeSpan(l.Range) } +// RangeSpan converts a UTF-16 range to a Span with both the +// position (line/col) and offset fields populated. func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) { start, err := m.Point(r.Start) if err != nil { @@ -183,22 +227,13 @@ func (m *ColumnMapper) RangeToSpanRange(r Range) (span.Range, error) { return spn.Range(m.TokFile) } -// Pos returns the token.Pos of p within the mapped file. +// Pos returns the token.Pos of protocol position p within the mapped file. func (m *ColumnMapper) Pos(p Position) (token.Pos, error) { start, err := m.Point(p) if err != nil { return token.NoPos, err } - // TODO: refactor the span package to avoid creating this unnecessary end position. - spn, err := span.New(m.URI, start, start).WithAll(m.TokFile) - if err != nil { - return token.NoPos, err - } - rng, err := spn.Range(m.TokFile) - if err != nil { - return token.NoPos, err - } - return rng.Start, nil + return safetoken.Pos(m.TokFile, start.Offset()) } // Offset returns the utf-8 byte offset of p within the mapped file. @@ -210,10 +245,12 @@ func (m *ColumnMapper) Offset(p Position) (int, error) { return start.Offset(), nil } -// Point returns a span.Point for p within the mapped file. The resulting point -// always has an Offset. +// Point returns a span.Point for the protocol position p within the mapped file. +// The resulting point has a valid Position and Offset. func (m *ColumnMapper) Point(p Position) (span.Point, error) { line := int(p.Line) + 1 + + // Find byte offset of start of containing line. offset, err := span.ToOffset(m.TokFile, line, 1) if err != nil { return span.Point{}, err diff --git a/gopls/internal/lsp/source/fix.go b/gopls/internal/lsp/source/fix.go index 1ce6d758b3..a4c6676cf0 100644 --- a/gopls/internal/lsp/source/fix.go +++ b/gopls/internal/lsp/source/fix.go @@ -93,15 +93,11 @@ func ApplyFix(ctx context.Context, fix string, snapshot Snapshot, fh VersionedFi if !end.IsValid() { end = edit.Pos } - spn, err := span.NewRange(tokFile, edit.Pos, end).Span() + fh, err := snapshot.GetVersionedFile(ctx, span.URIFromPath(tokFile.Name())) if err != nil { return nil, err } - fh, err := snapshot.GetVersionedFile(ctx, spn.URI()) - if err != nil { - return nil, err - } - te, ok := editsPerFile[spn.URI()] + te, ok := editsPerFile[fh.URI()] if !ok { te = &protocol.TextDocumentEdit{ TextDocument: protocol.OptionalVersionedTextDocumentIdentifier{ @@ -111,13 +107,13 @@ func ApplyFix(ctx context.Context, fix string, snapshot Snapshot, fh VersionedFi }, }, } - editsPerFile[spn.URI()] = te + editsPerFile[fh.URI()] = te } _, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage) if err != nil { return nil, err } - rng, err := pgf.Mapper.Range(spn) + rng, err := pgf.Mapper.PosRange(edit.Pos, end) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/source/util.go b/gopls/internal/lsp/source/util.go index b06992e482..c933fbadd0 100644 --- a/gopls/internal/lsp/source/util.go +++ b/gopls/internal/lsp/source/util.go @@ -17,7 +17,6 @@ import ( "strconv" "strings" - "golang.org/x/mod/modfile" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/gopls/internal/span" "golang.org/x/tools/internal/bug" @@ -26,6 +25,9 @@ import ( // MappedRange provides mapped protocol.Range for a span.Range, accounting for // UTF-16 code points. +// +// TOOD(adonovan): stop treating //line directives specially, and +// eliminate this type. All callers need either m, or a protocol.Range. type MappedRange struct { spanRange span.Range // the range in the compiled source (package.CompiledGoFiles) m *protocol.ColumnMapper // a mapper of the edited source (package.GoFiles) @@ -555,26 +557,6 @@ func IsCommandLineArguments(s string) bool { return strings.Contains(s, "command-line-arguments") } -// LineToRange creates a Range spanning start and end. -func LineToRange(m *protocol.ColumnMapper, uri span.URI, start, end modfile.Position) (protocol.Range, error) { - return ByteOffsetsToRange(m, uri, start.Byte, end.Byte) -} - -// ByteOffsetsToRange creates a range spanning start and end. -func ByteOffsetsToRange(m *protocol.ColumnMapper, uri span.URI, start, end int) (protocol.Range, error) { - line, col, err := span.ToPosition(m.TokFile, start) - if err != nil { - return protocol.Range{}, err - } - s := span.NewPoint(line, col, start) - line, col, err = span.ToPosition(m.TokFile, end) - if err != nil { - return protocol.Range{}, err - } - e := span.NewPoint(line, col, end) - return m.Range(span.New(uri, s, e)) -} - // RecvIdent returns the type identifier of a method receiver. // e.g. A for all of A, *A, A[T], *A[T], etc. func RecvIdent(recv *ast.FieldList) *ast.Ident { diff --git a/gopls/internal/lsp/text_synchronization.go b/gopls/internal/lsp/text_synchronization.go index 9687528c64..63bc0e8e56 100644 --- a/gopls/internal/lsp/text_synchronization.go +++ b/gopls/internal/lsp/text_synchronization.go @@ -356,6 +356,9 @@ func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, chan return nil, fmt.Errorf("%w: file not found (%v)", jsonrpc2.ErrInternal, err) } for _, change := range changes { + // TODO(adonovan): refactor to use diff.Apply, which is robust w.r.t. + // out-of-order or overlapping changes---and much more efficient. + // Make sure to update column mapper along with the content. m := protocol.NewColumnMapper(uri, content) if change.Range == nil { @@ -365,9 +368,6 @@ func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, chan if err != nil { return nil, err } - if !spn.HasOffset() { - return nil, fmt.Errorf("%w: invalid range for content change", jsonrpc2.ErrInternal) - } start, end := spn.Start().Offset(), spn.End().Offset() if end < start { return nil, fmt.Errorf("%w: invalid range for content change", jsonrpc2.ErrInternal) diff --git a/gopls/internal/lsp/work/diagnostics.go b/gopls/internal/lsp/work/diagnostics.go index 5d3a32897d..0d0f4eb18d 100644 --- a/gopls/internal/lsp/work/diagnostics.go +++ b/gopls/internal/lsp/work/diagnostics.go @@ -59,7 +59,7 @@ func DiagnosticsForWork(ctx context.Context, snapshot source.Snapshot, fh source // Add diagnostic if a directory does not contain a module. var diagnostics []*source.Diagnostic for _, use := range pw.File.Use { - rng, err := source.LineToRange(pw.Mapper, fh.URI(), use.Syntax.Start, use.Syntax.End) + rng, err := pw.Mapper.OffsetRange(use.Syntax.Start.Byte, use.Syntax.End.Byte) if err != nil { return nil, err } diff --git a/gopls/internal/lsp/work/hover.go b/gopls/internal/lsp/work/hover.go index ea4c1e58d9..641028b16e 100644 --- a/gopls/internal/lsp/work/hover.go +++ b/gopls/internal/lsp/work/hover.go @@ -11,9 +11,9 @@ import ( "go/token" "golang.org/x/mod/modfile" - "golang.org/x/tools/internal/event" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/gopls/internal/lsp/source" + "golang.org/x/tools/internal/event" ) func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.Hover, error) { @@ -56,7 +56,7 @@ func Hover(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, mod := pm.File.Module.Mod // Get the range to highlight for the hover. - rng, err := source.ByteOffsetsToRange(pw.Mapper, fh.URI(), pathStart, pathEnd) + rng, err := pw.Mapper.OffsetRange(pathStart, pathEnd) if err != nil { return nil, err } diff --git a/gopls/internal/span/span.go b/gopls/internal/span/span.go index 5b8d31ef03..333048ae8c 100644 --- a/gopls/internal/span/span.go +++ b/gopls/internal/span/span.go @@ -209,7 +209,8 @@ func (s Span) Format(f fmt.State, c rune) { } } -func (s Span) WithPosition(tf *token.File) (Span, error) { +// (Currently unused, but we gain little yet by deleting it.) +func (s Span) withPosition(tf *token.File) (Span, error) { if err := s.update(tf, true, false); err != nil { return Span{}, err } diff --git a/gopls/internal/span/utf16.go b/gopls/internal/span/utf16.go index f4c93a6ead..0f8e1bcacd 100644 --- a/gopls/internal/span/utf16.go +++ b/gopls/internal/span/utf16.go @@ -13,6 +13,9 @@ import ( // supplied file contents. // This is used to convert from the native (always in bytes) column // representation and the utf16 counts used by some editors. +// +// TODO(adonovan): this function is unused except by its test. Delete, +// or consolidate with (*protocol.ColumnMapper).utf16Column. func ToUTF16Column(p Point, content []byte) (int, error) { if !p.HasPosition() { return -1, fmt.Errorf("ToUTF16Column: point is missing position")