This page describes checks supported by wsl linter and how they should be resolved or configured to handle.
Anonymous switch
statements (mindless switch
) should deserve its needed
attention that it does not need any assigned variables. Hence, it should not
cuddle with anything before it. One bad example is:
timeout := 10
switch {
case s.Switches["bad timeout"]:
timeout = 100
case s.Switches["zero timeout"]:
timeout = 0
}
Add an empty line before the switch
statement:
timeout := 10
switch {
case s.Switches["bad timeout"]:
timeout = 100
case s.Switches["zero timeout"]:
timeout = 0
}
Can be configured, see configuration documentation
append
is only allowed to cuddle with the appended value. Otherwise, they
deserve some distance. If the variables you're assigning isn't going to be
appended (or used in the append, e.g. a function call), try to separate it.
x := []string{}
x = append(x, "literal")
notUsed := "just assigning, don't mind me"
x = append(x, "not z..")
useMe := "right away"
alsoNotUsed := ":("
x = append(x, "just noise"
x = append(x, useMe)
Things not going to be appended should not be cuddled in the append path (or a single append if only one). Variables being appended can be placed immediately before an append statement.
notUsed := "just assigning, don't mind me"
alsoNotUsed := ":("
x := []string{}
x = append(x, "literal")
x = append(x, "not z..")
x = append(x, "just noise"
useMe := "to be used"
x = append(x, useMe))
Can be configured, see configuration documentation
Assignments should either be grouped together or have some space between whoever
else before it. One bad example is z
and y
in such case:
if x == 1 {
x = 0
}
z := x + 2
fmt.Println("x")
y := "x"
Group all assignments together when possible (t
and x
). Otherwise, leave
an empty line before the assignment (e.g. z
).
if x == 1 {
x = 0
}
z := x + 2
y := "x"
fmt.Println("x")
Can be configured, see configuration documentation
Having an empty trailing whitespace is unnecessary and makes the block definition looks never-ending long. You want to let reader know that the code definitions end right after the last statement. Also, any trailing comments should be on the top. One bad example:
func example() string {
return fmt.Sprintf("x")
// TODO: add mux function later.
}
Remove the unnecessary trailing whitespace line (after return
statement).
Move the comment to the top.
func example(y int) string {
// TODO: add mux function later.
return fmt.Sprintf("x")
}
Can be configured, see configuration documentation
To improve readability WSL can force to add whitespaces based on a set limit. See link to configuration for options.
With force-case-trailing-whitespace
set to 1 this yields an error.
switch n {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
}
switch n {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
}
Having an empty leading whitespace is unnecessary and makes the block definition looks disconnected and long. You want to let reader to know that the code definitions start right after the block declaration. One bad example is:
func example() string {
return fmt.Sprintf("x")
}
Remove the unnecessary leading whitespace line (before x
definition).
func example() string {
return fmt.Sprintf("x")
}
However, this can be configured to allow white space after one or more initial comment groups, see configuration documentation
If that is done, then these examples are allowed:
func example() string {
// comment
return fmt.Sprintf("x")
}
and
func example() string {
// comment
// comment
return fmt.Sprintf("x")
}
Branch statements (break
, continue
, and return
) should stand out clearly
when the block is having more than or equal to 2 lines. Hence, it deserves
some spacing. One bad example is:
for i := range make([]int, 5) {
if i > 2 {
sendToOne(i)
sendToSecond(i)
continue
}
if statement == "is short" {
sendToOne(i)
break
}
}
Add an empty line before the branch statements (continue
) contained within
a more than or equal to 2 lines code block:
for i := range make([]int, 5) {
if i > 2 {
sendToOne(i)
sendToSecond(i)
continue
}
if statement == "is short" {
sendToOne(i)
break
}
}
Can be configured, see configuration documentation
var
declarations, in opinion, should never be cuddled. Instead, multiple
var
patterns is encouraged to use the grouped var
format. One case study is:
var eol string
var i int
Since this hit is opinionated, there are 3 ways to deal with it:
- Use the grouped
var
pattern:
var (
eol = ""
i = 0
)
-
Allow it by configuration (
wsl
orgolangci-lint
) -
Use an empty line between them
var eol = ""
var i = 0
defer
statement should only cuddle with related expressions. Otherwise, it
deserves some distance from whatever it is. One bad example is:
x := 4
defer notX()
Add an empty line before defer
:
x := 4
defer notX()
thisIsX := func() {}
defer thisIsX()
Code expressions should not be cuddled with a block (e.g. if
or switch
).
There must be some clarity between the block and the new expression itself.
One bad example is:
t, err := someFunc()
if err != nil {
// handle error
return
}
fmt.Println(t)
An empty line between the expression and block.
t, err := someFunc()
if err != nil {
// handle error
return
}
fmt.Println(t)
Any expressions should not cuddle with any declarations (var
) or return
.
They deserve some space for clarity. One bad example is (run()
):
var i int
run()
return i
run()
Give an empty after the declaration (var
) and an empty line before the
return
:
var i int
run()
return i
run()
for
loop without conditions (infinity loop) should deserves its own
attention. Hence, it should not be cuddled with anyone.
x := "hey"
for {
fmt.Printf("x")
}
Add an empty line before the for
loop.
x := "hey"
for {
fmt.Printf("x")
}
for
statement should only cuddle with related assignments. Otherwise, its
relationship status can be very complicated, making reader wondering what the
co-relation between the for
block and whatever it is. One bad example is:
x := y + 2
for i := 0; i < y+10; i++ {
fmt.Println(i)
}
list := getList()
for i, v := range anotherList {
fmt.Println(i)
}
Add an empty line before the for
statement:
x := y + 2
for i := 0; i < y+10; i++ {
fmt.Printf("this is i:%v\n", i)
}
step := 2
for i := 0; i < y+10; i+=step {
fmt.Printf("this is i:%v\n", i)
}
list := getList()
for i, v := range list {
fmt.Printf("%d: %s\n", i, v)
}
go
statement deserves clarity from any nearby non-related executions. Hence,
it deserves an empty line separation before it.
thisIsFunc := func() {}
go thisIsNOTFunc()
Add an empty before go
statement.
thisIsFunc := func() {}
go thisIsFunc()
thisIsNOTFunc := func() {}
go callingAnotherFunc()
if
statement should only cuddle with one related assignment. Otherwise, it
should have a distance between if
and whoever else is.
one := 1
if 1 == 1 {
fmt.Println("duuh")
}
if 1 != one {
fmt.Println("i don't believe you!")
}
Group that single related assignment together with the if
block and give one
empty line before them.
If environment is not allowed like mutex lock blocking
(e.g. Intercept(...)
), add an empty line before the if
block.
if 1 == 1 {
fmt.Println("duuh")
}
one := 1
if 1 != one {
fmt.Println("i don't believe you!")
}
if
statements should only cuddle with the associated assignment. Otherwise,
it deserves some space between itself and whoever before it. One bad example is
the if
block that uses x
cuddled with z
assignment:
x := true
if true {
fmt.Println("didn't use cuddled variable")
}
Shift the if
block close to the assignment when possible (if
with x
).
Otherwise, leave an empty line before it (if
uses y
):
y := true
if true {
fmt.Println("didn't use cuddled variable")
}
x := false
if !x {
fmt.Println("proper usage of variable")
}
Can be configured, see configuration documentation
When an assignment is cuddling with an unrelated expression, they create
confusing relationship to one another. Therefore, they should keep their
distance. One bad example (all fmt
printouts):
notInExpression := GetIt()
call.SomethingElse()
Provide an empty line before the expression:
notInExpression := GetIt()
call.SomethingElse()
thisIsBetter := GetIt()
thisIsBetter.CallIt()
defer
statement should only be cuddled with 1 related assignment. If you have
more than 1 assignment(s), they should have a space between them for clarity
purposes. One bad example is:
assignmentOne := Something()
assignmentTwo := AnotherThing()
defer assignmentTwo()
EXCEPTION: It is allowed to use the following:
- The
defer
aftererror
check as reported in Issue #31f1, err := os.Open("/path/to/f1.txt") if err != nil { // handle error return -1 } defer f1.Close()
OR
- The conventional mutex
Lock
andUnlock
.m.Lock() defer m.Unlock()
Add an empty line before defer
:
assignmentOne := Something()
assignmentTwo := AnotherThing()
defer assignmentTwo()
for
block should only be cuddled with 1 related assignment. If you have more
than 1 assignment(s), they should have a space between them for clarity
purposes. One bad example is:
i := 0
a := 0
for i = 0; i < 5; i++ {
fmt.Println("x")
}
An empty line between the last assignment and the for
block.
i := 0
a := 0
for i = 0; i < 5; i++ {
fmt.Println("x")
}
j := 0
for i = 0; j < 5; i++ {
fmt.Println("x")
}
go
block should only be cuddled with 1 related assignment. If you have more
than 1 assignment(s), they should have a space between them for clarity
purposes. One bad example is:
assignOne := SomeOne()
assignTwo := SomeTwo()
go assignTwo()
An empty line between the last assignment and the go
block.
assignOne := SomeOne()
assignTwo := SomeTwo()
go assignTwo()
If block should only be cuddled with 1 related assignment. If you have more than 1 assignment(s), they should have more space between them for clarity purposes. One bad example is:
lengthA := len(sliceA)
lengthB := len(sliceB)
if lengthA != lengthB {
fmt.Println("not equal")
}
An empty line between the last assignment and the if
block.
lengthA := len(sliceA)
lengthB := len(sliceB)
if lengthA != lengthB {
fmt.Println("not equal")
}
lengthC := len(sliceC)
if lengthC > 1 {
fmt.Println("only one assignment is ok")
}
range
block should only be cuddled with 1 related assignment. If you have more
than 1 assignment(s), they should have more space between them for clarity
purposes. One bad example is:
listA := GetA()
listB := GetB()
for _, v := range listB {
fmt.Println(v)
}
Give an empty line before range
statement:
listA := GetA()
listB := GetB()
for _, v := range listB {
fmt.Println(v)
}
listC := GetC()
for _, v := range listC {
fmt.Println(v)
}
switch
block should only be cuddled with 1 related assignment. If you have
more than 1 assignment(s), they should have more space between them for clarity
purposes. One bad example is:
assignOne := SomeOne()
assignTwo := SomeTwo()
switch assignTwo {
case 1:
fmt.Println("one")
default:
fmt.Println("NOT one")
}
An empty line between the last assignment and the switch
block:
assignOne := SomeOne()
assignTwo := SomeTwo()
switch assignTwo {
case 1:
fmt.Println("one")
default:
fmt.Println("NOT one")
}
assignThree := SomeThree()
switch assignTwo {
// cases
}
type
switch
block should only be cuddled with 1 related assignment. If you
have more than 1 assignment(s), they should have more space between them for
clarity purposes.
someT := GetT()
anotherT := GetT()
switch v := anotherT.(type) {
case int:
fmt.Println("was int")
default:
fmt.Println("was not int")
}
An empty line between the last assignment and the switch
block.
someT := GetT()
anotherT := GetT()
switch v := anotherT.(type) {
case int:
fmt.Println("was int")
default:
fmt.Println("was not int")
}
thirdT := GetT()
switch v := thirdT.(type)
// cases
}
range
statements should only cuddle with assignments related to it. Otherwise,
it creates unrelated relationship perception that sends the reader to wonder
why are they closely together. One bad example is:
y := []string{"a", "b", "c"}
x := 5
for _, v := range y {
fmt.Println(v)
}
Either group the related assignment together with the range
block and
add an empty line before them (first range
) OR an empty line before the
range
block (second range
):
y := []string{"a", "b", "c"}
for _, v := range y {
fmt.Println(v)
}
// May also cuddle if used first in block
t2 := []string{}
for _, v := range y {
t2 = append(t2, v)
}
return
statement should not be cuddled if the function block is not a
2-lines block. Otherwise, there should be a clarity with return
line. If
the function block is single/double lines, the return
statement can be
cuddled.
func F1(x int) (s string) {
switch x {
case 1:
s = "one"
case 2:
s = "two"
case 3:
s = "three"
}
return s
}
An empty line between return
and multi-line block or no empty line between
return
and single-line block.
func F1(x int) (s string) {
switch x {
case 1:
s = "one"
case 2:
s = "two"
case 3:
s = "three"
}
return s
}
func PlusFifteenAsString(y int) string {
y += 15
return fmt.Sprintf("%s", y)
}
func IsNotZero(i int) bool {
return i != 0
}
switch
statements with associated switching variable should not cuddle with
non-associated switching entity. This will set the reader wondering why are
they grouped together at the first place. One bad example is:
notInSwitch := ""
switch someThingElse {
case 1:
fmt.Println("one")
case 2:
fmt.Println("one")
case 3:
fmt.Println("three")
}
Group related assignment together and add an empty line before them OR add an
empty line before the switch
:
notInSwitch := ""
switch someThingElse {
case 1:
fmt.Println("one")
case 2:
fmt.Println("one")
case 3:
fmt.Println("three")
}
inSwitch := 2
switch inSwitch {
case 1:
fmt.Println("better")
}
type
switch
statements should only cuddle with its switching variable.
Otherwise, it makes unclear relationship between the switch
block and whatever
before it. Here is a bad example:
notInSwitch := GetSomeType()
switch someThingElse.(type) {
case int:
fmt.Println("int")
default:
fmt.Println("not int")
}
Give an empty line before the switch
statement:
notInSwitch := GetSomeType()
switch someThingElse.(type) {
case int:
fmt.Println("int")
default:
fmt.Println("not int")
}
inSwitch := GetSomeType()
switch inSwitch.(type) {
// cases
}
Can be configured, see configuration documentation
When an if
statement checks a variable named err
, which was assigned on the line above, it should be cuddled with that assignment. This makes clear the relationship between the error check and the call that may have resulted in an error.
err := ErrorProducingFunc()
if err != nil {
return err
}
Remove the empty line between the assignment and the error check.
err := ErrorProducingFunc()
if err != nil {
return err
}
Can be configured, see configuration documentation
A short declaration (an "assignment" using :=
) must not be cuddled with anything other than another short declaration.
a := 1
err := ErrorProducingFunc()
if err != nil {
return err
}
Add an empty line between the short declaration and the error check.
a := 1
err := ErrorProducingFunc()
if err != nil {
return err
}
Note: this is the opposite of the case above forcing an err
variable
to be assigned together with its check; it also overrides some other rules
which about assignments by separating short declarations from "plain"
assignment statements using =
.