Add WSL linter (#771)

* Add WSL linter

* Use v1.0.0 tag for wsl

* Don't add specific test file skip, use mutex to add errors

* Fix goimports error

* Add more tests for WSL, bump WSL version

* Fix bad go.sum (go mod tidy)
This commit is contained in:
Simon Sawert 2019-10-04 22:03:40 +02:00 committed by Trevor Pounds
parent 30864f8818
commit 3e09174bd2
17 changed files with 1685 additions and 3 deletions

View File

@ -222,6 +222,7 @@ stylecheck: Stylecheck is a replacement for golint [fast: true, auto-fix: false]
unconvert: Remove unnecessary type conversions [fast: true, auto-fix: false]
unparam: Reports unused function parameters [fast: true, auto-fix: false]
whitespace: Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
wsl: Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
```
Pass `-E/--enable` to enable linter and `-D/--disable` to disable:
@ -469,6 +470,7 @@ golangci-lint help linters
- [godox](https://github.com/matoous/godox) - Tool for detection of FIXME, TODO and other comment keywords
- [funlen](https://github.com/ultraware/funlen) - Tool for detection of long functions
- [whitespace](https://github.com/ultraware/whitespace) - Tool for detection of leading and trailing whitespace
- [wsl](https://github.com/bombsimon/wsl) - Whitespace Linter - Forces you to use empty lines!
## Configuration
@ -1123,6 +1125,7 @@ Thanks to developers and authors of used linters:
- [leighmcculloch](https://github.com/leighmcculloch)
- [matoous](https://github.com/matoous)
- [ultraware](https://github.com/ultraware)
- [bombsimon](https://github.com/bombsimon)
## Changelog

3
go.mod
View File

@ -4,6 +4,7 @@ go 1.12
require (
github.com/OpenPeeDeeP/depguard v1.0.1
github.com/bombsimon/wsl v1.0.1
github.com/fatih/color v1.7.0
github.com/go-critic/go-critic v0.3.5-0.20190904082202-d79a9f0c64db
github.com/go-lintpack/lintpack v0.5.2
@ -40,7 +41,7 @@ require (
github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517
github.com/valyala/quicktemplate v1.2.0
golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678
gopkg.in/yaml.v2 v2.2.2
gopkg.in/yaml.v2 v2.2.4
honnef.co/go/tools v0.0.1-2019.2.3
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect

4
go.sum
View File

@ -11,6 +11,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bombsimon/wsl v1.0.1 h1:GkrpOj7ajds8re6EJXN+k6UtatYSktupigQ2ZfOUIOU=
github.com/bombsimon/wsl v1.0.1/go.mod h1:DSRwCD8c7NecM11/LnZcTS8nS8OND5ybj04DWM4l8mc=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -308,6 +310,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

63
pkg/golinters/wsl.go Normal file
View File

@ -0,0 +1,63 @@
package golinters
import (
"sync"
"github.com/bombsimon/wsl"
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
)
const (
name = "wsl"
)
// NewWSL returns a new WSL linter.
func NewWSL() *goanalysis.Linter {
var (
issues []result.Issue
mu = sync.Mutex{}
analyzer = &analysis.Analyzer{
Name: goanalysis.TheOnlyAnalyzerName,
Doc: goanalysis.TheOnlyanalyzerDoc,
}
)
return goanalysis.NewLinter(
name,
"Whitespace Linter - Forces you to use empty lines!",
[]*analysis.Analyzer{analyzer},
nil,
).WithContextSetter(func(lintCtx *linter.Context) {
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
files := []string{}
for _, file := range pass.Files {
files = append(files, pass.Fset.Position(file.Pos()).Filename)
}
wslErrors, _ := wsl.ProcessFiles(files)
if len(wslErrors) == 0 {
return nil, nil
}
mu.Lock()
defer mu.Unlock()
for _, err := range wslErrors {
issues = append(issues, result.Issue{
FromLinter: name,
Pos: err.Position,
Text: err.Reason,
})
}
return nil, nil
}
}).WithIssuesReporter(func(*linter.Context) []result.Issue {
return issues
}).WithLoadMode(goanalysis.LoadModeSyntax)
}

View File

@ -204,6 +204,9 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetStyle).
WithAutoFix().
WithURL("https://github.com/ultraware/whitespace"),
linter.NewConfig(golinters.NewWSL()).
WithPresets(linter.PresetStyle).
WithURL("https://github.com/bombsimon/wsl"),
}
isLocalRun := os.Getenv("GOLANGCI_COM_RUN") == ""

80
test/testdata/wsl.go vendored Normal file
View File

@ -0,0 +1,80 @@
//args: -Ewsl
//config: linters-settings.wsl.tests=1
package testdata
import (
"context"
"fmt"
)
func main() {
var (
y = 0
)
if y < 1 { // ERROR "if statements should only be cuddled with assignments"
fmt.Println("tight")
}
thisIsNotUsedInIf := true
if 2 > 1 { // ERROR "if statements should only be cuddled with assignments used in the if statement itself"
return
}
one := 1
two := 2
three := 3
if three == 3 { // ERROR "only one cuddle assignment allowed before if statement"
fmt.Println("too many cuddled assignments", one, two, thisIsNotUsedInIf)
}
var a = "a"
var b = "b" // ERROR "declarations should never be cuddled"
if true {
return
}
if false { // ERROR "if statements should only be cuddled with assignments"
return
}
for i := range make([]int, 10) {
fmt.Println(i)
fmt.Println(i + i)
continue // ERROR "branch statements should not be cuddled if block has more than two lines"
}
assignOne := a
fmt.Println(assignOne)
assignTwo := b // ERROR "assignments should only be cuddled with other assignments"
fmt.Println(assignTwo)
_, cf1 := context.WithCancel(context.Background())
_, cf2 := context.WithCancel(context.Background())
defer cf1() // ERROR "only one cuddle assignment allowed before defer statement"
defer cf2()
}
func f1() int {
x := 1
return x
}
func f2() int {
x := 1
y := 3
return x + y // ERROR "return statements should not be cuddled if block has more than two lines"
}
func f3() int {
sum := 0
for _, v := range []int{2, 4, 8} {
sum += v
}
notSum := 0
for _, v := range []int{1, 2, 4} { // ERROR "ranges should only be cuddled with assignments used in the iteration"
sum += v
}
return sum + notSum
}

70
vendor/github.com/bombsimon/wsl/.gitignore generated vendored Normal file
View File

@ -0,0 +1,70 @@
# Created by https://www.gitignore.io/api/go,vim,macos
### Go ###
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
### Go Patch ###
/vendor/
/Godeps/
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
# End of https://www.gitignore.io/api/go,vim,macos

25
vendor/github.com/bombsimon/wsl/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,25 @@
---
language: go
go:
- "1.13"
- "1.12"
- "1.11"
env:
global:
- GO111MODULE=on
install:
- go get -v golang.org/x/tools/cmd/cover github.com/mattn/goveralls
script:
- go test -v -covermode=count -coverprofile=coverage.out
after_script:
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
notifications:
email: false
# vim: set ts=2 sw=2 et:

21
vendor/github.com/bombsimon/wsl/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Simon Sawert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

594
vendor/github.com/bombsimon/wsl/README.md generated vendored Normal file
View File

@ -0,0 +1,594 @@
# WSL - Whitespace Linter
[![forthebadge](https://forthebadge.com/images/badges/made-with-go.svg)](https://forthebadge.com)
[![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com)
[![Build Status](https://travis-ci.org/bombsimon/wsl.svg?branch=master)](https://travis-ci.org/bombsimon/wsl)
[![Coverage Status](https://coveralls.io/repos/github/bombsimon/wsl/badge.svg?branch=master)](https://coveralls.io/github/bombsimon/wsl?branch=master)
WSL is a linter that enforces a very **non scientific** vision of how to make
code more readable by enforcing empty lines at the right places.
I think too much code out there is to cuddly and a bit too warm for it's own
good, making it harder for other people to read and understand. The linter will
warn about newlines in and around blocks, in the beginning of files and other
places in the code.
## Usage
Install by using `go get -u github.com/bombsimon/wsl/cmd/...`.
Run with `wsl [--no-test] <file1> [files...]` or `wsl ./package/...`. The "..."
wildcard is not used like other `go` commands but instead can only be to a
relative or absolute path.
By default, the linter will run on `./...` which means all go files in the
current path and all subsequent paths, including test files. To disable linting
test files, use `-n` or `--no-test`.
## Rules
Note that this linter doesn't take in consideration the issues that will be
fixed with `gofmt` so ensure that the code is properly formatted.
### Never use empty lines
Even though this linter was built to **promote** the usage of empty lines, there
are a few places where they should never be used.
Never use empty lines in the start or end of a block!
**Don't**
```go
if someBooleanValue {
fmt.Println("i like starting newlines")
}
if someOtherBooleanValue {
fmt.Println("also trailing")
}
switch {
case 1:
fmt.Println("switch is also a block")
}
switch {
case 1:
fmt.Println("not in a case")
case 2:
fmt.Println("or at the end")
}
func neverNewlineAfterReturn() {
return true
}
func notEvenWithComments() {
return false
// I just forgot to say this...
}
```
**Do**
```go
if someBooleanValue {
fmt.Println("this is tight and nice")
}
switch {
case 1:
fmt.Println("no blank lines here")
case 2:
// Comments are fine here!
fmt.Println("or here")
}
func returnCuddleded() {
// My comment goes above the last statement!
return true
}
```
### Use empty lines
There's an easy way to improve logic and readability by enforcing whitespaces at
the right places. Usually this is around blocks and after declarations.
#### If
If statements should only be cuddled with assignments/declarations of variables
used in the condition and only one assignment should be cuddled. Never cuddle if
with anything but assignments.
**Don't**
```go
notConditional := "x"
if somethingElse == "y" {
fmt.Println("what am i checking?")
}
first := 1
second := 2
third := 3
forever := 4
if forever {
return true
}
if false {
fmt.Println("first if")
}
if true {
fmt.Println("second if is cuddled")
}
```
**Do**
```go
val, err := SomeThing()
if err != nil {
// err is assigned on line above
}
first := 1
second := 2
third := 3
forever := 4
if forever > 3 {
return fmt.Sprintf("group multiple assignments away from if")
}
// Or separate from your condition.
first := 1
second := 2
third := 3
forever := 4
if forever > 3 {
return fmt.Sprintf("group multiple assignments away from if")
}
if false {
// This is one statement
}
if true {
// This is another one, don't cuddled them!
}
```
#### Return
Return should be placed on a separate line from other statement unless the block
consists of only two lines (including the return).
**Don't**
```go
doSomething()
add := 1+2
fmt.Sprintf(add)
return false
if true {
stmt.X = true
stmt.Y = false
return true
}
```
**Do**
```go
doSomething()
add := 1+2
fmt.Sprintf(add))
return false
if true {
stmt.X = "only one line without return, may cuddled"
return true
}
if thisWorksToo {
whitespace := true
return false
}
```
#### Branch statement
The same rule as for return
**Don't**
```go
for i := range make([]int, 5) {
if i > 2 {
sendToOne(i)
sendToSecond(i)
continue
}
}
```
**Do**
```go
for i := range make([]int, 5) {
if i > 2 {
sendToOne(i)
sendToSecond(i)
continue
}
if statement == "is short" {
sendToOne(i)
break
}
}
```
#### Assignment
Assignments may only be cuddled with other assignments.
**Don't**
```go
assignOne := "one"
callFunc(assignOne)
assignTwo := "two")
callFunc(assignTwo)
if true {
return
}
assigningClose := "bad"
var x = 2
y := 3
```
**Do**
```go
assignOne := "one"
assignTwo := "two")
callFunc(assignOne)
callFunc(assignTwo)
// Or group assignment and call by usage.
assignOne := "one"
callFunc(assignOne)
assignTwo := "two")
callFunc(assignTwo)
if true {
return
}
notAssigningClose := "not bad"
var x = 2
y := 3
```
#### Declarations
Declarations should never be cuddled with anything, not even other declarations.
**Don't**
```go
var x int
var y int
z := 2
var a
```
**Do**
```go
// Group declarations, they'll align nice and tidy!
var (
x int
y int
)
z := 2
var a
```
#### Expressions
Expressions (function calls) may never be cuddled with declarations or return
statements. Expressions may also not be cuddled with assignments if not passed
to the expression func.
**Don't**
```go
var a bool
fmt.Println(a)
foo := true
someFunc(false)
```
**Do**
```go
var b bool
fmt.Println(b)
foo := true
someFunc(foo)
bar := false
someFunc(true)
```
#### Ranges
Range statements may only be cuddled with assignments that are used in the
range. Just like if statements this only applies if it's a single assignment
cuddled and not multiple.
Ranges may also be cuddled with assignments that are used directly in the block
as first statement.
**Don't**
```go
noRangeList := []string{"a", "b", "c"}
for _, x := range anotherList {
fmt.Println(x)
}
oneList := []int{1, 2, 3}
twoList := []int{4, 5, 6}
for i := range twoList {
fmt.Println("too much assignments!")
}
myCount := 0
for _, v := range aList {
fmt.Sprintf("first statement doesn't use assignment")
}
```
**Do**
```go
rangeList := []string{"a", "b", "c"}
for _, x := range rangeList {
fmt.Println(x)
}
oneList := []int{1, 2, 3}
twoList := []int{4, 5, 6}
for i := range twoList {
fmt.Println("too much assignments!")
}
myCount := 0
for _, v := range aList {
myCount += v
fmt.Sprintf("first statement uses cuddled assignment")
}
```
#### Defer
Defer is almost handled like return statements but there are cases where
grouping defer statements with each other or expression calls may improve
readability.
Defer statements may be cuddled with other defer statements as many times as you
like. It may also be cuddled with assignments above or expression variables on
the line above.
**Don't**
```go
first := getFirst()
defer first.Close()
second := getSecond() // This will fail
defer second.Close()
first := getFirst()
second := getSecond()
defer first.Close() // Too many assignments above
defer second.Close()
m1.Lock()
defer m2.RUnlock() // Not the expression above
```
**Do**
```go
first := getFirst()
second := getSecond()
defer first.Close()
defer second.Close()
// Or group by usage.
first := getFirst()
defer first.Close()
second := getSecond()
defer second.Close()
m.Lock()
defer m.Unlock()
```
#### For loops
For statements works similar like ranges except that anonymous (infinite) loops
may never be cuddled. Just like the range statement, variables used in the for
or in first statement in the body may be cuddled.
**Don't**
```go
t := true
for notT {
fmt.Println("where's t used?")
}
n := 0
m := 1
for x < 100 {
n += x // m not used in for or body
}
n := 1
for {
fmt.Println("never cuddled for without condition")
}
```
**Do**
```go
t := true
for t {
fmt.Println("t used in for")
}
n := 0
for x < 100 {
n += x // n used in first block statement.
}
n := 1
for {
fmt.Println("never cuddled for without condition")
}
```
#### Go
Go routines may only be executed if there's a maximum of one assignments above
and that assignment is used in the expression.
**Don't**
```go
first := func() {}
second := func() {}
go second()
notUsed := func() {}
go first()
x := "1"
go func() {
fmt.Println("where's x used!=")
}()
```
**Do**
```go
first := func() {}
go first()
notUsed := func() {}
first := func() {}
go first()
```
#### Switch and Type switch
The same rules applies for switch and type switch statements with the exception
of anonymous type switches. That means type switches where a new variable is not
assigned. It's also allowed to cuddled type switches with variables used if it's
used as the first argument in the first case.
Type switches may only be cuddled with one assignment above and if that
assignment is used in the switch.
**Don't**
```go
notSome := SomeInt()
switch some {
case 1:
fmt.Println("1")
default:
fmt.Println("not 1")
}
notSwitched := SomeInt()
switch {
case 1 > 2:
fmt.Println("whitespace between assignments")
}
n := 0
switch v := some.(type):
case typeOne:
x := v.X // n not used in switch or body
case typeTwo:
x := v.X
}
```
**Do**
```go
some := SomeInt()
switch some {
case 1:
fmt.Println("1")
default:
fmt.Println("not 1")
}
notSwitched := SomeInt()
switch {
case 1 > 2:
fmt.Println("whitespace between assignments")
}
n := 0
switch v := some.(type):
case typeOne:
n = v.X // n is used first in block, OK to cuddle
case typeTwo:
n = v.Y
}
```

11
vendor/github.com/bombsimon/wsl/go.mod generated vendored Normal file
View File

@ -0,0 +1,11 @@
module github.com/bombsimon/wsl
require (
github.com/davecgh/go-spew v1.1.1
github.com/kr/pretty v0.1.0 // indirect
github.com/stretchr/testify v1.4.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.4 // indirect
)
go 1.11

24
vendor/github.com/bombsimon/wsl/go.sum generated vendored Normal file
View File

@ -0,0 +1,24 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

727
vendor/github.com/bombsimon/wsl/wsl.go generated vendored Normal file
View File

@ -0,0 +1,727 @@
package wsl
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"reflect"
)
type result struct {
FileName string
LineNumber int
Position token.Position
Reason string
}
type processor struct {
result []result
warnings []string
fileSet *token.FileSet
file *ast.File
}
// ProcessFiles takes a string slice with file names (full paths) and lints
// them.
func ProcessFiles(filenames []string) ([]result, []string) {
p := NewProcessor()
// Iterate over all files.
for _, filename := range filenames {
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
p.process(filename, data)
}
return p.result, p.warnings
}
// NewProcessor will create a processor.
func NewProcessor() *processor {
return &processor{
result: []result{},
}
}
func (p *processor) process(filename string, data []byte) {
fileSet := token.NewFileSet()
file, err := parser.ParseFile(fileSet, filename, data, parser.ParseComments)
// If the file is not parsable let's add a syntax error and move on.
if err != nil {
p.result = append(p.result, result{
FileName: filename,
LineNumber: 0,
Reason: fmt.Sprintf("invalid syntax, file cannot be linted (%s)", err.Error()),
})
return
}
p.fileSet = fileSet
p.file = file
for _, d := range p.file.Decls {
switch v := d.(type) {
case *ast.FuncDecl:
p.parseBlockBody(v.Body)
case *ast.GenDecl:
// `go fmt` will handle proper spacing for GenDecl such as imports,
// constants etc.
default:
p.addWarning("type not implemented", d.Pos(), v)
}
}
}
// parseBlockBody will parse any kind of block statements such as switch cases
// and if statements. A list of Result is returned.
func (p *processor) parseBlockBody(block *ast.BlockStmt) {
// Nothing to do if there's no value.
if reflect.ValueOf(block).IsNil() {
return
}
// Start by finding leading and trailing whitespaces.
p.findLeadingAndTrailingWhitespaces(block, nil)
// Parse the block body contents.
p.parseBlockStatements(block.List)
}
// parseBlockStatements will parse all the statements found in the body of a
// node. A list of Result is returned.
func (p *processor) parseBlockStatements(statements []ast.Stmt) {
for i, stmt := range statements {
// TODO: How to tell when and where func literals may exist to enforce
// linting.
if as, isAssignStmt := stmt.(*ast.AssignStmt); isAssignStmt {
for _, rhs := range as.Rhs {
if fl, isFuncLit := rhs.(*ast.FuncLit); isFuncLit {
p.parseBlockBody(fl.Body)
}
}
}
firstBodyStatement := p.firstBodyStatement(i, statements)
// First statement, nothing to do.
if i == 0 {
continue
}
previousStatement := statements[i-1]
// If the last statement didn't end one line above the current statement
// we know we're not cuddled so just move on.
if p.nodeEnd(previousStatement) != p.nodeStart(stmt)-1 {
continue
}
// We know we're cuddled, extract assigned variables on the line above
// which is the only thing we allow cuddling with. If the assignment is
// made over multiple lines we should not allow cuddling.
var assignedOnLineAbove []string
// Ensure previous line is not a multi line assignment and if not get
// all assigned variables.
if p.nodeStart(previousStatement) == p.nodeStart(stmt)-1 {
assignedOnLineAbove = p.findLhs(previousStatement)
}
// We could potentially have a block which require us to check the first
// argument before ruling out an allowed cuddle.
var assignedFirstInBlock []string
if firstBodyStatement != nil {
assignedFirstInBlock = p.findLhs(firstBodyStatement)
}
lhs := p.findLhs(stmt)
rhs := p.findRhs(stmt)
all := append(lhs, rhs...)
/*
DEBUG:
fmt.Println("LHS: ", lhs)
fmt.Println("RHS: ", rhs)
fmt.Println("Assigned above: ", assignedOnLineAbove)
fmt.Println("Assigned first: ", assignedFirstInBlock)
*/
moreThanOneStatementAbove := func() bool {
if i < 2 {
return false
}
statementBeforePreviousStatement := statements[i-2]
if p.nodeStart(previousStatement)-1 == p.nodeEnd(statementBeforePreviousStatement) {
return true
}
return false
}
isLastStatementInBlockOfOnlyTwoLines := func() bool {
// If we're the last statement, check if there's no more than two
// lines from the starting statement and the end of this statement.
// This is to support short return functions such as:
// func (t *Typ) X() {
// t.X = true
// return t
// }
if i == len(statements)-1 && i == 1 {
if p.nodeEnd(stmt)-p.nodeStart(previousStatement) <= 2 {
return true
}
}
return false
}
switch t := stmt.(type) {
case *ast.IfStmt:
if len(assignedOnLineAbove) == 0 {
p.addError(t.Pos(), "if statements should only be cuddled with assignments")
continue
}
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before if statement")
continue
}
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
if !atLeastOneInListsMatch(assignedOnLineAbove, assignedFirstInBlock) {
p.addError(t.Pos(), "if statements should only be cuddled with assignments used in the if statement itself")
}
}
case *ast.ReturnStmt:
if isLastStatementInBlockOfOnlyTwoLines() {
continue
}
p.addError(t.Pos(), "return statements should not be cuddled if block has more than two lines")
case *ast.BranchStmt:
if isLastStatementInBlockOfOnlyTwoLines() {
continue
}
p.addError(t.Pos(), "branch statements should not be cuddled if block has more than two lines")
case *ast.AssignStmt:
// append is usually an assignment but should not be allowed to be
// cuddled with anything not appended.
if len(rhs) > 0 && rhs[len(rhs)-1] == "append" {
if !atLeastOneInListsMatch(assignedOnLineAbove, rhs) {
p.addError(t.Pos(), "append only allowed to cuddle with appended value")
}
}
if _, ok := previousStatement.(*ast.AssignStmt); ok {
continue
}
p.addError(t.Pos(), "assignments should only be cuddled with other assignments")
case *ast.DeclStmt:
p.addError(t.Pos(), "declarations should never be cuddled")
case *ast.ExprStmt:
switch previousStatement.(type) {
case *ast.DeclStmt, *ast.ReturnStmt:
p.addError(t.Pos(), "expressions should not be cuddled with declarations or returns")
}
// If we assigned variables on the line above but didn't use them in
// this expression we there should probably be a newline between
// them.
if len(assignedOnLineAbove) > 0 && !atLeastOneInListsMatch(all, assignedOnLineAbove) {
p.addError(t.Pos(), "only cuddled expressions if assigning variable or using from line above")
}
case *ast.RangeStmt:
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before range statement")
continue
}
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
if !atLeastOneInListsMatch(assignedOnLineAbove, assignedFirstInBlock) {
p.addError(t.Pos(), "ranges should only be cuddled with assignments used in the iteration")
}
}
case *ast.DeferStmt:
if _, ok := previousStatement.(*ast.DeferStmt); ok {
// We may cuddle multiple defers to group logic.
continue
}
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before defer statement")
continue
}
// Be extra nice with RHS, it's common to use this for locks:
// m.Lock()
// defer m.Unlock()
previousRhs := p.findRhs(previousStatement)
if atLeastOneInListsMatch(rhs, previousRhs) {
continue
}
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
p.addError(t.Pos(), "defer statements should only be cuddled with expressions on same variable")
}
case *ast.ForStmt:
if len(all) == 0 {
p.addError(t.Pos(), "for statement without condition should never be cuddled")
continue
}
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before for statement")
continue
}
// The same rule applies for ranges as for if statements, see
// comments regarding variable usages on the line before or as the
// first line in the block for details.
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
if !atLeastOneInListsMatch(assignedOnLineAbove, assignedFirstInBlock) {
p.addError(t.Pos(), "for statements should only be cuddled with assignments used in the iteration")
}
}
case *ast.GoStmt:
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before go statement")
continue
}
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
p.addError(t.Pos(), "go statements can only invoke functions assigned on line above")
}
case *ast.SwitchStmt:
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before switch statement")
continue
}
if !atLeastOneInListsMatch(all, assignedOnLineAbove) {
if len(all) == 0 {
p.addError(t.Pos(), "anonymous switch statements should never be cuddled")
} else {
p.addError(t.Pos(), "switch statements should only be cuddled with variables switched")
}
}
case *ast.TypeSwitchStmt:
if moreThanOneStatementAbove() {
p.addError(t.Pos(), "only one cuddle assignment allowed before type switch statement")
continue
}
// Allowed to type assert on variable assigned on line above.
if !atLeastOneInListsMatch(rhs, assignedOnLineAbove) {
// Allow type assertion on variables used in the first case
// immediately.
if !atLeastOneInListsMatch(assignedOnLineAbove, assignedFirstInBlock) {
p.addError(t.Pos(), "type switch statements should only be cuddled with variables switched")
}
}
case *ast.CaseClause, *ast.CommClause:
// Case clauses will be checked by not allowing leading ot trailing
// whitespaces within the block. There's nothing in the case itself
// that may be cuddled.
default:
p.addWarning("stmt type not implemented", t.Pos(), t)
}
}
}
// firstBodyStatement returns the first statement inside a body block. This is
// because variables may be cuddled with conditions or statements if it's used
// directly as the first argument inside a body.
// The body will then be parsed as a *ast.BlockStmt (regular block) or as a list
// of []ast.Stmt (case block).
func (p *processor) firstBodyStatement(i int, allStmt []ast.Stmt) ast.Node {
stmt := allStmt[i]
// Start by checking if the statement has a body (probably if-statement,
// a range, switch case or similar. Whenever a body is found we start by
// parsing it before moving on in the AST.
statementBody := reflect.Indirect(reflect.ValueOf(stmt)).FieldByName("Body")
// Some cases allow cuddling depending on the first statement in a body
// of a block or case. If possible extract the first statement.
var firstBodyStatement ast.Node
if !statementBody.IsValid() {
return firstBodyStatement
}
switch statementBodyContent := statementBody.Interface().(type) {
case *ast.BlockStmt:
if len(statementBodyContent.List) > 0 {
firstBodyStatement = statementBodyContent.List[0]
// If the first body statement is a *ast.CaseClause we're
// actually interested in the **next** body to know what's
// inside the first case.
if x, ok := firstBodyStatement.(*ast.CaseClause); ok {
if len(x.Body) > 0 {
firstBodyStatement = x.Body[0]
}
}
}
p.parseBlockBody(statementBodyContent)
case []ast.Stmt:
// The Body field for an *ast.CaseClause or *ast.CommClause is of type
// []ast.Stmt. We must check leading and trailing whitespaces and then
// pass the statements to parseBlockStatements to parse it's content.
var nextStatement ast.Node
// Check if there's more statements (potential cases) after the
// current one.
if len(allStmt)-1 > i {
nextStatement = allStmt[i+1]
}
p.findLeadingAndTrailingWhitespaces(stmt, nextStatement)
p.parseBlockStatements(statementBodyContent)
default:
p.addWarning(
"body statement type not implemented ",
stmt.Pos(), statementBodyContent,
)
}
return firstBodyStatement
}
func (p *processor) findLhs(node ast.Node) []string {
var lhs []string
if node == nil {
return lhs
}
switch t := node.(type) {
case *ast.BasicLit, *ast.FuncLit, *ast.SelectStmt,
*ast.LabeledStmt, *ast.ForStmt, *ast.SwitchStmt,
*ast.ReturnStmt, *ast.GoStmt, *ast.CaseClause,
*ast.CommClause, *ast.CallExpr, *ast.UnaryExpr,
*ast.BranchStmt, *ast.TypeSpec, *ast.ChanType,
*ast.DeferStmt, *ast.TypeAssertExpr, *ast.IncDecStmt,
*ast.RangeStmt:
// Nothing to add to LHS
case *ast.Ident:
return []string{t.Name}
case *ast.AssignStmt:
for _, v := range t.Lhs {
lhs = append(lhs, p.findLhs(v)...)
}
case *ast.GenDecl:
for _, v := range t.Specs {
lhs = append(lhs, p.findLhs(v)...)
}
case *ast.ValueSpec:
for _, v := range t.Names {
lhs = append(lhs, p.findLhs(v)...)
}
case *ast.BlockStmt:
for _, v := range t.List {
lhs = append(lhs, p.findLhs(v)...)
}
case *ast.BinaryExpr:
return append(
p.findLhs(t.X),
p.findLhs(t.Y)...,
)
case *ast.DeclStmt:
return p.findLhs(t.Decl)
case *ast.IfStmt:
return p.findLhs(t.Cond)
case *ast.TypeSwitchStmt:
return p.findLhs(t.Assign)
case *ast.SendStmt:
return p.findLhs(t.Chan)
default:
if x, ok := maybeX(t); ok {
return p.findLhs(x)
}
p.addWarning("UNKNOWN LHS", t.Pos(), t)
}
return lhs
}
func (p *processor) findRhs(node ast.Node) []string {
var rhs []string
if node == nil {
return rhs
}
switch t := node.(type) {
case *ast.BasicLit, *ast.SelectStmt, *ast.ChanType,
*ast.LabeledStmt, *ast.DeclStmt, *ast.BranchStmt,
*ast.TypeSpec, *ast.ArrayType, *ast.CaseClause,
*ast.CommClause, *ast.KeyValueExpr, *ast.MapType,
*ast.FuncLit:
// Nothing to add to RHS
case *ast.Ident:
return []string{t.Name}
case *ast.SelectorExpr:
// TODO: Should this be RHS?
// Needed for defer as of now
return p.findRhs(t.X)
case *ast.AssignStmt:
for _, v := range t.Rhs {
rhs = append(rhs, p.findRhs(v)...)
}
case *ast.CallExpr:
for _, v := range t.Args {
rhs = append(rhs, p.findRhs(v)...)
}
rhs = append(rhs, p.findRhs(t.Fun)...)
case *ast.CompositeLit:
for _, v := range t.Elts {
rhs = append(rhs, p.findRhs(v)...)
}
case *ast.IfStmt:
rhs = append(rhs, p.findRhs(t.Cond)...)
rhs = append(rhs, p.findRhs(t.Init)...)
case *ast.BinaryExpr:
return append(
p.findRhs(t.X),
p.findRhs(t.Y)...,
)
case *ast.TypeSwitchStmt:
return p.findRhs(t.Assign)
case *ast.ReturnStmt:
for _, v := range t.Results {
rhs = append(rhs, p.findRhs(v)...)
}
case *ast.BlockStmt:
for _, v := range t.List {
rhs = append(rhs, p.findRhs(v)...)
}
case *ast.SwitchStmt:
return p.findRhs(t.Tag)
case *ast.GoStmt:
return p.findRhs(t.Call)
case *ast.ForStmt:
return p.findRhs(t.Cond)
case *ast.DeferStmt:
return p.findRhs(t.Call)
case *ast.SendStmt:
return p.findLhs(t.Value)
default:
if x, ok := maybeX(t); ok {
return p.findRhs(x)
}
p.addWarning("UNKNOWN RHS", t.Pos(), t)
}
return rhs
}
// maybeX extracts the X field from an AST node and returns it with a true value
// if it exists. If the node doesn't have an X field nil and false is returned.
// Known fields with X that are handled:
// IndexExpr, ExprStmt, SelectorExpr, StarExpr, ParentExpr, TypeAssertExpr,
// RangeStmt, UnaryExpr, ParenExpr, SLiceExpr, IncDecStmt.
func maybeX(node interface{}) (ast.Node, bool) {
maybeHasX := reflect.Indirect(reflect.ValueOf(node)).FieldByName("X")
if !maybeHasX.IsValid() {
return nil, false
}
n, ok := maybeHasX.Interface().(ast.Node)
if !ok {
return nil, false
}
return n, true
}
func atLeastOneInListsMatch(listOne, listTwo []string) bool {
sliceToMap := func(s []string) map[string]struct{} {
m := map[string]struct{}{}
for _, v := range s {
m[v] = struct{}{}
}
return m
}
m1 := sliceToMap(listOne)
m2 := sliceToMap(listTwo)
for k1 := range m1 {
if _, ok := m2[k1]; ok {
return true
}
}
for k2 := range m2 {
if _, ok := m1[k2]; ok {
return true
}
}
return false
}
// findLeadingAndTrailingWhitespaces will find leading and trailing whitespaces
// in a node. The method takes comments in consideration which will make the
// parser more gentle.
func (p *processor) findLeadingAndTrailingWhitespaces(stmt, nextStatement ast.Node) {
var (
allowedLinesBeforeFirstStatement = 1
commentMap = ast.NewCommentMap(p.fileSet, stmt, p.file.Comments)
blockStatements []ast.Stmt
blockStartLine int
blockEndLine int
)
// Depending on the block type, get the statements in the block and where
// the block starts (and ends).
switch t := stmt.(type) {
case *ast.BlockStmt:
blockStatements = t.List
blockStartLine = p.fileSet.Position(t.Lbrace).Line
blockEndLine = p.fileSet.Position(t.Rbrace).Line
case *ast.CaseClause:
blockStatements = t.Body
blockStartLine = p.fileSet.Position(t.Colon).Line
case *ast.CommClause:
blockStatements = t.Body
blockStartLine = p.fileSet.Position(t.Colon).Line
default:
p.addWarning("whitespace node type not implemented ", stmt.Pos(), stmt)
return
}
// Ignore empty blocks even if they have newlines or just comments.
if len(blockStatements) < 1 {
return
}
var (
firstStatement = blockStatements[0]
lastStatement = blockStatements[len(blockStatements)-1]
)
// Get the comment related to the first statement, we do allow commends in
// the beginning of a block before the first statement.
if c, ok := commentMap[firstStatement]; ok {
for _, commentGroup := range c {
var (
start = p.fileSet.Position(commentGroup.Pos()).Line
)
// If the comment group is on the same lince as the block start
// (LBrace) we should not consider it.
if start == blockStartLine {
continue
}
// We only care about comments before our statement from the comment
// map. As soon as we hit comments after our statement let's break
// out!
if commentGroup.Pos() > firstStatement.Pos() {
break
}
allowedLinesBeforeFirstStatement += len(commentGroup.List)
}
}
if p.fileSet.Position(firstStatement.Pos()).Line != blockStartLine+allowedLinesBeforeFirstStatement {
p.addErrorOffset(
firstStatement.Pos(),
-1,
"block should not start with a whitespace",
)
}
// If the blockEndLine is 0 we're a case clause. If we don't have any
// nextStatement the trailing whitespace will be handled when parsing the
// switch. If we do have a next statement we can see where it starts by
// getting it's colon position.
if blockEndLine == 0 {
if nextStatement == nil {
return
}
switch n := nextStatement.(type) {
case *ast.CaseClause:
blockEndLine = p.fileSet.Position(n.Colon).Line
case *ast.CommClause:
blockEndLine = p.fileSet.Position(n.Colon).Line
default:
// We're not at the end of the case?
return
}
}
if p.fileSet.Position(lastStatement.End()).Line != blockEndLine-1 {
p.addErrorOffset(
lastStatement.End(),
1,
"block should not end with a whitespace (or comment)",
)
}
}
func (p *processor) nodeStart(node ast.Node) int {
return p.fileSet.Position(node.Pos()).Line
}
func (p *processor) nodeEnd(node ast.Node) int {
return p.fileSet.Position(node.End()).Line
}
// Add an error for the file and line number for the current token.Pos with the
// given reason.
func (p *processor) addError(pos token.Pos, reason string) {
p.addErrorOffset(pos, 0, reason)
}
// Add an error for the file for the current token.Pos with the given offset and
// reason. The offset will be added to the token.Pos line.
func (p *processor) addErrorOffset(pos token.Pos, offset int, reason string) {
position := p.fileSet.Position(pos)
p.result = append(p.result, result{
FileName: position.Filename,
LineNumber: position.Line + offset,
Position: position,
Reason: reason,
})
}
func (p *processor) addWarning(w string, pos token.Pos, t interface{}) {
position := p.fileSet.Position(pos)
p.warnings = append(p.warnings,
fmt.Sprintf("%s:%d: %s (%T)", position.Filename, position.Line, w, t),
)
}

38
vendor/gopkg.in/yaml.v2/decode.go generated vendored
View File

@ -229,6 +229,10 @@ type decoder struct {
mapType reflect.Type
terrors []string
strict bool
decodeCount int
aliasCount int
aliasDepth int
}
var (
@ -314,7 +318,39 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm
return out, false, false
}
const (
// 400,000 decode operations is ~500kb of dense object declarations, or ~5kb of dense object declarations with 10000% alias expansion
alias_ratio_range_low = 400000
// 4,000,000 decode operations is ~5MB of dense object declarations, or ~4.5MB of dense object declarations with 10% alias expansion
alias_ratio_range_high = 4000000
// alias_ratio_range is the range over which we scale allowed alias ratios
alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
)
func allowedAliasRatio(decodeCount int) float64 {
switch {
case decodeCount <= alias_ratio_range_low:
// allow 99% to come from alias expansion for small-to-medium documents
return 0.99
case decodeCount >= alias_ratio_range_high:
// allow 10% to come from alias expansion for very large documents
return 0.10
default:
// scale smoothly from 99% down to 10% over the range.
// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
}
}
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
d.decodeCount++
if d.aliasDepth > 0 {
d.aliasCount++
}
if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
failf("document contains excessive aliasing")
}
switch n.kind {
case documentNode:
return d.document(n, out)
@ -353,7 +389,9 @@ func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
failf("anchor '%s' value contains itself", n.value)
}
d.aliases[n] = true
d.aliasDepth++
good = d.unmarshal(n.alias, out)
d.aliasDepth--
delete(d.aliases, n)
return good
}

2
vendor/gopkg.in/yaml.v2/resolve.go generated vendored
View File

@ -81,7 +81,7 @@ func resolvableTag(tag string) bool {
return false
}
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
func resolve(tag string, in string) (rtag string, out interface{}) {
if !resolvableTag(tag) {

16
vendor/gopkg.in/yaml.v2/scannerc.go generated vendored
View File

@ -906,6 +906,9 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
return true
}
// max_flow_level limits the flow_level
const max_flow_level = 10000
// Increase the flow level and resize the simple key list if needed.
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
// Reset the simple key on the next level.
@ -913,6 +916,11 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
// Increase the flow level.
parser.flow_level++
if parser.flow_level > max_flow_level {
return yaml_parser_set_scanner_error(parser,
"while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
fmt.Sprintf("exceeded max depth of %d", max_flow_level))
}
return true
}
@ -925,6 +933,9 @@ func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
return true
}
// max_indents limits the indents stack size
const max_indents = 10000
// Push the current indentation level to the stack and set the new level
// the current column is greater than the indentation level. In this case,
// append or insert the specified token into the token queue.
@ -939,6 +950,11 @@ func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml
// indentation level.
parser.indents = append(parser.indents, parser.indent)
parser.indent = column
if len(parser.indents) > max_indents {
return yaml_parser_set_scanner_error(parser,
"while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
fmt.Sprintf("exceeded max depth of %d", max_indents))
}
// Create a token and insert it into the queue.
token := yaml_token_t{

4
vendor/modules.txt vendored
View File

@ -4,6 +4,8 @@ github.com/BurntSushi/toml
github.com/OpenPeeDeeP/depguard
# github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6
github.com/StackExchange/wmi
# github.com/bombsimon/wsl v1.0.1
github.com/bombsimon/wsl
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
# github.com/fatih/color v1.7.0
@ -238,7 +240,7 @@ golang.org/x/tools/internal/gopathwalk
golang.org/x/tools/internal/imports
golang.org/x/tools/internal/module
golang.org/x/tools/internal/semver
# gopkg.in/yaml.v2 v2.2.2
# gopkg.in/yaml.v2 v2.2.4
gopkg.in/yaml.v2
# honnef.co/go/tools v0.0.1-2019.2.3
honnef.co/go/tools/arg