Golangci-lint v2 part two (#498)

This commit is contained in:
Vincent Serpoul
2021-04-15 22:29:46 +08:00
committed by GitHub
parent 9e122af5fc
commit 59cddbc573
2 changed files with 88 additions and 38 deletions
+66 -28
View File
@@ -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
View File
@@ -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())
}) })
} }