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:
parent
30864f8818
commit
3e09174bd2
@ -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
3
go.mod
@ -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
4
go.sum
@ -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
63
pkg/golinters/wsl.go
Normal 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)
|
||||
}
|
@ -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
80
test/testdata/wsl.go
vendored
Normal 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
70
vendor/github.com/bombsimon/wsl/.gitignore
generated
vendored
Normal 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
25
vendor/github.com/bombsimon/wsl/.travis.yml
generated
vendored
Normal 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
21
vendor/github.com/bombsimon/wsl/LICENSE
generated
vendored
Normal 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
594
vendor/github.com/bombsimon/wsl/README.md
generated
vendored
Normal file
@ -0,0 +1,594 @@
|
||||
# WSL - Whitespace Linter
|
||||
|
||||
[](https://forthebadge.com)
|
||||
[](https://forthebadge.com)
|
||||
|
||||
[](https://travis-ci.org/bombsimon/wsl)
|
||||
[](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
11
vendor/github.com/bombsimon/wsl/go.mod
generated
vendored
Normal 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
24
vendor/github.com/bombsimon/wsl/go.sum
generated
vendored
Normal 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
727
vendor/github.com/bombsimon/wsl/wsl.go
generated
vendored
Normal 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
38
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
@ -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
2
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
@ -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
16
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
@ -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
4
vendor/modules.txt
vendored
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user