From 6536af71d98a5bb8f2cbd2f5e62afc2f6cc93dbb Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Mon, 7 Oct 2019 13:52:07 -0400 Subject: [PATCH] internal/span: end of file is now last line +1 We already accepted it as a valid input, but for output we still produced last_line,last_column+1 Also add package docs and improve error messages Change-Id: I017aa326e8392134e67e8fabec47e750c8055454 Reviewed-on: https://go-review.googlesource.com/c/tools/+/199641 Run-TryBot: Ian Cottrell TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/span/span.go | 5 +++++ internal/span/token.go | 11 +++++++---- internal/span/token_test.go | 9 ++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/internal/span/span.go b/internal/span/span.go index b66bd7a5e0..4d2ad09866 100644 --- a/internal/span/span.go +++ b/internal/span/span.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package span contains support for representing with positions and ranges in +// text files. package span import ( @@ -34,6 +36,9 @@ type point struct { Offset int `json:"offset"` } +// Invalid is a span that reports false from IsValid +var Invalid = Span{v: span{Start: invalidPoint.v, End: invalidPoint.v}} + var invalidPoint = Point{v: point{Line: 0, Column: 0, Offset: -1}} // Converter is the interface to an object that can convert between line:column diff --git a/internal/span/token.go b/internal/span/token.go index 4efd0c80e6..ce44541b2f 100644 --- a/internal/span/token.go +++ b/internal/span/token.go @@ -102,10 +102,10 @@ func (s Span) Range(converter *TokenConverter) (Range, error) { // go/token will panic if the offset is larger than the file's size, // so check here to avoid panicking. if s.Start().Offset() > converter.file.Size() { - return Range{}, fmt.Errorf("start offset %v is past the end of the file", s.Start()) + return Range{}, fmt.Errorf("start offset %v is past the end of the file %v", s.Start(), converter.file.Size()) } if s.End().Offset() > converter.file.Size() { - return Range{}, fmt.Errorf("end offset %v is past the end of the file", s.End()) + return Range{}, fmt.Errorf("end offset %v is past the end of the file %v", s.End(), converter.file.Size()) } return Range{ FileSet: converter.fset, @@ -116,10 +116,13 @@ func (s Span) Range(converter *TokenConverter) (Range, error) { func (l *TokenConverter) ToPosition(offset int) (int, int, error) { if offset > l.file.Size() { - return 0, 0, fmt.Errorf("offset %v is past the end of the file", offset) + return 0, 0, fmt.Errorf("offset %v is past the end of the file %v", offset, l.file.Size()) } pos := l.file.Pos(offset) p := l.fset.Position(pos) + if offset == l.file.Size() { + return p.Line + 1, 1, nil + } return p.Line, p.Column, nil } @@ -129,7 +132,7 @@ func (l *TokenConverter) ToOffset(line, col int) (int, error) { } lineMax := l.file.LineCount() + 1 if line > lineMax { - return -1, fmt.Errorf("line is beyond end of file") + return -1, fmt.Errorf("line is beyond end of file %v", lineMax) } else if line == lineMax { if col > 1 { return -1, fmt.Errorf("column is beyond end of file") diff --git a/internal/span/token_test.go b/internal/span/token_test.go index 7e5b467490..c9fce771d7 100644 --- a/internal/span/token_test.go +++ b/internal/span/token_test.go @@ -24,14 +24,17 @@ package test // // // file b.go -package test -`)}, +package test`)}, + {"/c.go", []byte(` +// file c.go +package test`)}, } var tokenTests = []span.Span{ span.New(span.FileURI("/a.go"), span.NewPoint(1, 1, 0), span.Point{}), span.New(span.FileURI("/a.go"), span.NewPoint(3, 7, 20), span.NewPoint(3, 7, 20)), span.New(span.FileURI("/b.go"), span.NewPoint(4, 9, 15), span.NewPoint(4, 13, 19)), + span.New(span.FileURI("/c.go"), span.NewPoint(4, 1, 26), span.Point{}), } func TestToken(t *testing.T) { @@ -70,6 +73,6 @@ func checkToken(t *testing.T, c *span.TokenConverter, in, expect span.Span) { expected := fmt.Sprintf("%+v", expect) got := fmt.Sprintf("%+v", gotLoc) if expected != got { - t.Errorf("Expected %q got %q", expected, got) + t.Errorf("For %v expected %q got %q", in, expected, got) } }