Golangci-lint v2 part two (#498)
This commit is contained in:
@@ -50,7 +50,7 @@ func (e *DecodeError) String() string {
|
|||||||
return e.human
|
return e.human
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Position returns the (line, column) pair indicating where the error
|
// Position returns the (line, column) pair indicating where the error
|
||||||
// occurred in the document. Positions are 1-indexed.
|
// occurred in the document. Positions are 1-indexed.
|
||||||
func (e *DecodeError) Position() (row int, column int) {
|
func (e *DecodeError) Position() (row int, column int) {
|
||||||
return e.line, e.column
|
return e.line, e.column
|
||||||
@@ -63,110 +63,147 @@ func (e *DecodeError) Position() (row int, column int) {
|
|||||||
//
|
//
|
||||||
// The function copies all bytes used in DecodeError, so that document and
|
// The function copies all bytes used in DecodeError, so that document and
|
||||||
// highlight can be freely deallocated.
|
// highlight can be freely deallocated.
|
||||||
|
//nolint:funlen
|
||||||
func wrapDecodeError(document []byte, de *decodeError) error {
|
func wrapDecodeError(document []byte, de *decodeError) error {
|
||||||
if de == nil {
|
if de == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := &DecodeError{
|
|
||||||
message: de.message,
|
|
||||||
}
|
|
||||||
|
|
||||||
offset := unsafe.SubsliceOffset(document, de.highlight)
|
offset := unsafe.SubsliceOffset(document, de.highlight)
|
||||||
|
|
||||||
err.line, err.column = positionAtEnd(document[:offset])
|
errMessage := de.message
|
||||||
|
errLine, errColumn := positionAtEnd(document[:offset])
|
||||||
before, after := linesOfContext(document, de.highlight, offset, 3)
|
before, after := linesOfContext(document, de.highlight, offset, 3)
|
||||||
|
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
|
|
||||||
maxLine := err.line + len(after) - 1
|
maxLine := errLine + len(after) - 1
|
||||||
lineColumnWidth := len(strconv.Itoa(maxLine))
|
lineColumnWidth := len(strconv.Itoa(maxLine))
|
||||||
|
|
||||||
for i := len(before) - 1; i > 0; i-- {
|
for i := len(before) - 1; i > 0; i-- {
|
||||||
line := err.line - i
|
line := errLine - i
|
||||||
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
||||||
buf.WriteString("| ")
|
buf.WriteString("|")
|
||||||
buf.Write(before[i])
|
|
||||||
|
if len(before[i]) > 0 {
|
||||||
|
buf.WriteString(" ")
|
||||||
|
buf.Write(before[i])
|
||||||
|
}
|
||||||
|
|
||||||
buf.WriteRune('\n')
|
buf.WriteRune('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(formatLineNumber(err.line, lineColumnWidth))
|
buf.WriteString(formatLineNumber(errLine, lineColumnWidth))
|
||||||
buf.WriteString("| ")
|
buf.WriteString("| ")
|
||||||
|
|
||||||
if len(before) > 0 {
|
if len(before) > 0 {
|
||||||
buf.Write(before[0])
|
buf.Write(before[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.Write(de.highlight)
|
buf.Write(de.highlight)
|
||||||
|
|
||||||
if len(after) > 0 {
|
if len(after) > 0 {
|
||||||
buf.Write(after[0])
|
buf.Write(after[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteRune('\n')
|
buf.WriteRune('\n')
|
||||||
buf.WriteString(strings.Repeat(" ", lineColumnWidth))
|
buf.WriteString(strings.Repeat(" ", lineColumnWidth))
|
||||||
buf.WriteString("| ")
|
buf.WriteString("| ")
|
||||||
|
|
||||||
if len(before) > 0 {
|
if len(before) > 0 {
|
||||||
buf.WriteString(strings.Repeat(" ", len(before[0])))
|
buf.WriteString(strings.Repeat(" ", len(before[0])))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(strings.Repeat("~", len(de.highlight)))
|
buf.WriteString(strings.Repeat("~", len(de.highlight)))
|
||||||
buf.WriteString(" ")
|
|
||||||
buf.WriteString(err.message)
|
if len(errMessage) > 0 {
|
||||||
|
buf.WriteString(" ")
|
||||||
|
buf.WriteString(errMessage)
|
||||||
|
}
|
||||||
|
|
||||||
for i := 1; i < len(after); i++ {
|
for i := 1; i < len(after); i++ {
|
||||||
buf.WriteRune('\n')
|
buf.WriteRune('\n')
|
||||||
line := err.line + i
|
line := errLine + i
|
||||||
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
buf.WriteString(formatLineNumber(line, lineColumnWidth))
|
||||||
buf.WriteString("| ")
|
buf.WriteString("|")
|
||||||
buf.Write(after[i])
|
|
||||||
|
if len(after[i]) > 0 {
|
||||||
|
buf.WriteString(" ")
|
||||||
|
buf.Write(after[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err.human = buf.String()
|
return &DecodeError{
|
||||||
return err
|
message: errMessage,
|
||||||
|
line: errLine,
|
||||||
|
column: errColumn,
|
||||||
|
human: buf.String(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatLineNumber(line int, width int) string {
|
func formatLineNumber(line int, width int) string {
|
||||||
format := "%" + strconv.Itoa(width) + "d"
|
format := "%" + strconv.Itoa(width) + "d"
|
||||||
|
|
||||||
return fmt.Sprintf(format, line)
|
return fmt.Sprintf(format, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func linesOfContext(document []byte, highlight []byte, offset int, linesAround int) ([][]byte, [][]byte) {
|
func linesOfContext(document []byte, highlight []byte, offset int, linesAround int) ([][]byte, [][]byte) {
|
||||||
|
return beforeLines(document, offset, linesAround), afterLines(document, highlight, offset, linesAround)
|
||||||
|
}
|
||||||
|
|
||||||
|
func beforeLines(document []byte, offset int, linesAround int) [][]byte {
|
||||||
var beforeLines [][]byte
|
var beforeLines [][]byte
|
||||||
|
|
||||||
// Walk the document in reverse from the highlight to find previous lines
|
// Walk the document backward from the highlight to find previous lines
|
||||||
// of context.
|
// of context.
|
||||||
rest := document[:offset]
|
rest := document[:offset]
|
||||||
|
backward:
|
||||||
for o := len(rest) - 1; o >= 0 && len(beforeLines) <= linesAround && len(rest) > 0; {
|
for o := len(rest) - 1; o >= 0 && len(beforeLines) <= linesAround && len(rest) > 0; {
|
||||||
if rest[o] == '\n' {
|
switch {
|
||||||
|
case rest[o] == '\n':
|
||||||
// handle individual lines
|
// handle individual lines
|
||||||
beforeLines = append(beforeLines, rest[o+1:])
|
beforeLines = append(beforeLines, rest[o+1:])
|
||||||
rest = rest[:o]
|
rest = rest[:o]
|
||||||
o = len(rest) - 1
|
o = len(rest) - 1
|
||||||
} else if o == 0 {
|
case o == 0:
|
||||||
// add the first line only if it's non-empty
|
// add the first line only if it's non-empty
|
||||||
beforeLines = append(beforeLines, rest)
|
beforeLines = append(beforeLines, rest)
|
||||||
break
|
|
||||||
} else {
|
break backward
|
||||||
|
default:
|
||||||
o--
|
o--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return beforeLines
|
||||||
|
}
|
||||||
|
|
||||||
|
func afterLines(document []byte, highlight []byte, offset int, linesAround int) [][]byte {
|
||||||
var afterLines [][]byte
|
var afterLines [][]byte
|
||||||
|
|
||||||
// Walk the document forward from the highlight to find the following
|
// Walk the document forward from the highlight to find the following
|
||||||
// lines of context.
|
// lines of context.
|
||||||
rest = document[offset+len(highlight):]
|
rest := document[offset+len(highlight):]
|
||||||
|
forward:
|
||||||
for o := 0; o < len(rest) && len(afterLines) <= linesAround; {
|
for o := 0; o < len(rest) && len(afterLines) <= linesAround; {
|
||||||
if rest[o] == '\n' {
|
switch {
|
||||||
|
case rest[o] == '\n':
|
||||||
// handle individual lines
|
// handle individual lines
|
||||||
afterLines = append(afterLines, rest[:o])
|
afterLines = append(afterLines, rest[:o])
|
||||||
rest = rest[o+1:]
|
rest = rest[o+1:]
|
||||||
o = 0
|
o = 0
|
||||||
} else if o == len(rest)-1 && o > 0 {
|
|
||||||
|
case o == len(rest)-1 && o > 0:
|
||||||
// add last line only if it's non-empty
|
// add last line only if it's non-empty
|
||||||
afterLines = append(afterLines, rest)
|
afterLines = append(afterLines, rest)
|
||||||
break
|
|
||||||
} else {
|
break forward
|
||||||
|
default:
|
||||||
o++
|
o++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return beforeLines, afterLines
|
|
||||||
|
return afterLines
|
||||||
}
|
}
|
||||||
|
|
||||||
func positionAtEnd(b []byte) (row int, column int) {
|
func positionAtEnd(b []byte) (row int, column int) {
|
||||||
@@ -181,5 +218,6 @@ func positionAtEnd(b []byte) (row int, column int) {
|
|||||||
column++
|
column++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-10
@@ -2,13 +2,17 @@ package toml
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestDecodeError(t *testing.T) {
|
func TestDecodeError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
doc [3]string
|
doc [3]string
|
||||||
@@ -103,7 +107,7 @@ should not be seen4`},
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "last line of more than 10",
|
desc: "last line of more than 10",
|
||||||
doc: [3]string{`should not be seen
|
doc: [3]string{`should not be seen
|
||||||
should not be seen
|
should not be seen
|
||||||
should not be seen
|
should not be seen
|
||||||
should not be seen
|
should not be seen
|
||||||
@@ -125,7 +129,8 @@ before `, "highlighted", ``},
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "handle empty lines in the before/after blocks",
|
desc: "handle empty lines in the before/after blocks",
|
||||||
doc: [3]string{`line1
|
doc: [3]string{
|
||||||
|
`line1
|
||||||
|
|
||||||
line 2
|
line 2
|
||||||
before `, "highlighted", ` after
|
before `, "highlighted", ` after
|
||||||
@@ -134,21 +139,21 @@ line 3
|
|||||||
line 4
|
line 4
|
||||||
line 5`,
|
line 5`,
|
||||||
},
|
},
|
||||||
expected: `
|
expected: `1| line1
|
||||||
1| line1
|
2|
|
||||||
2|
|
|
||||||
3| line 2
|
3| line 2
|
||||||
4| before highlighted after
|
4| before highlighted after
|
||||||
| ~~~~~~~~~~~
|
| ~~~~~~~~~~~
|
||||||
5| line 3
|
5| line 3
|
||||||
6|
|
6|
|
||||||
7| line 4
|
7| line 4`,
|
||||||
`,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
b := bytes.Buffer{}
|
b := bytes.Buffer{}
|
||||||
b.Write([]byte(e.doc[0]))
|
b.Write([]byte(e.doc[0]))
|
||||||
start := b.Len()
|
start := b.Len()
|
||||||
@@ -162,7 +167,14 @@ line 5`,
|
|||||||
highlight: hl,
|
highlight: hl,
|
||||||
message: e.msg,
|
message: e.msg,
|
||||||
})
|
})
|
||||||
derr := err.(*DecodeError)
|
|
||||||
|
var derr *DecodeError
|
||||||
|
if !errors.As(err, &derr) {
|
||||||
|
t.Errorf("error not in expected format")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(t, strings.Trim(e.expected, "\n"), derr.String())
|
assert.Equal(t, strings.Trim(e.expected, "\n"), derr.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user