Source code analyzer that helps you to make your Go programs more consistent.

go-consistent

Build Status Go Report Card

Source code analyzer that helps you to make your Go programs more consistent.

Quick start / Installation

This install go-consistent binary under your $GOPATH/bin:

go get github.com/quasilyte/go-consistent

If $GOPATH/bin is under your system $PATH, go-consistent command should be available after that.
This should print the help message:

go-consistent --help

You can pass package names and separate Go filenames to the go-consistent tool:

go-consistent foo.go bar.go mypkg

You can also use std, ./... and other conventional targets that are normally understood by Go tools.

  • If you want to check consistency of a single file or package, just provide their name
  • If you want to check the whole project, you should pass all its packages as an arguments

Suppose your project occupies separate $GOPATH, then you can check the entire project by doing:

cd $(go env GOPATH)/src
go-consistent -v ./...

Overview

To understand what go-consistent does, take a look at these 3 lines of code:

lit1 := map[K]V{}
lit2 := map[K]V{}
m := make(map[K]V)

lit1, lit2 and m are initialized to an empty, non-nil map. The problem is that you have at least 2 ways to do it:

  1. lit1 and lit2 use the first option, the map literal
  2. m uses the second option, the make function

Neither of these are the "best", but on the package or project level, you might want to prefer only one of them, for consistency reasons.

go-consistent tool detects that map literal used more frequently (2 vs 1) in the example above, so it suggest you to replace m initialization expression to use map literal instead of make function.

There are many similar cases where you have 2 or more options of expressing the same thing in Go, go-consistent tries to handle as much patterns as possible.

Project traits

  • Zero-configuration. Defaults should be good enough for most users. Other configuration is performed using command line arguments.
  • Can handle projects of any size. This means that there should be no significant memory consumption growth with the increased number of packages being checked. There can be "fast, but memory-hungry" option that can work best for small-average projects, but it should be always possible to check huge projects on the developer machine.

Complete list of checks performed

  1. unit import
  2. zero val ptr alloc
  3. empty slice
  4. empty map
  5. hex lit
  6. range check
  7. and-not
  8. float lit
  9. label case
  10. untyped const coerce
  11. arg list parens
  12. non-zero length test
  13. default case order

unit import

// A: no parenthesis
import "fmt"

// B: with parenthesis
import (
	"fmt"
)

zero val ptr alloc

// A: new call
new(T)
new([]T)

// B: address of literal
&T{}
&[]T{}

empty slice

// A: make call
make([]T, 0)

// B: slice literal
[]T{}

empty map

// A: make call
make(map[K]V)

// B: map literal
map[K]V{}

hex lit

// A: lower case a-f digits
0xff

// B: upper case A-F digits
0xFF

range check

// A: left-aligned
x > low && x < high

// B: center-aligned
low < x && x < high

and-not

// A: using &^ operator (no space)
x &^ y

// B: using & and ^ (with space)
x & ^y

float lit

// A: explicit int/frac parts
0.0
1.0

// B: implicit int/frac parts
.0
1.

label case

// A: all upper case
LABEL_NAME:

// B: upper camel case
LabelName:

// C: lower camel case
labelName:

untyped const coerce

// A: LHS type
var x int32 = 10
const y float32 = 1.6

// B: RHS type
var x = int32(10)
const y = float32(1.6)

arg list parens

// A: closing parenthesis on the same line
multiLineCall(
	a,
	b,
	c)

// B: closing parenthesis on the next line
multiLineCall(
	a,
	b,
	c,
)

non-zero length test

// A: compare as "number of elems not equal to zero"
len(xs) != 0

// B: compare as "more than 0 elements"
len(xs) > 0

// C: compare as "at least 1 element"
len(xs) >= 1

default case order

// A: default case is the first one
switch {
default:
	return "?"
case x > 10:
	return "more than 10"
}

// B: default case is the last one
switch {
case x > 10:
	return "more than 10"
default:
	return "?"
}
Owner
Comments
  • go-consistent should ignore generated files

    go-consistent should ignore generated files

    Sometimes, generated files will be caught by go-consistent, since the source of these files should not be checked. See golang/go#13560 for more information about the standard way to detect generated code.

  • Fix multiple matches for different op variants

    Fix multiple matches for different op variants

    Single node can cause multiple variants to be matched. This increases multiple counters for conflicting variants => this is a bug. Variants should be matched sequentially, one after another, until any of them matches.

  • update golang.org/x/tools to fix error on go 1.14

    update golang.org/x/tools to fix error on go 1.14

    From go 1.14, an error occurs:

    internal error: nil Pkg importing "go/ast" from "github.com/quasilyte/go-consistent [github.com/quasilyte/go-consistent.test]"
    

    To fix this, update x/tools:

    go get golang.org/x/tools && go mod tidy
    

    Related: https://github.com/golang/go/issues/33554

  • Investigate duplicated checker output

    Investigate duplicated checker output

    During the https://github.com/go-critic/go-critic check, there were duplicated warning messages. Seems like go/packages is still not used properly.

    go-consistent output:

    $GOPATH/src/github.com/go-critic/go-critic/cmd/criticize/main.go:198:15: empty map: use make(map[K]V)
    $GOPATH/src/github.com/go-critic/go-critic/cmd/criticize/main.go:246:35: arg list parens: align `)` to a same line with last argument
    $GOPATH/src/github.com/go-critic/go-critic/cmd/lintwalk/main.go:73:14: empty map: use make(map[K]V)
    $GOPATH/src/github.com/go-critic/go-critic/lint/defaultCaseOrder_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/lint_private.go:20:25: empty map: use make(map[K]V)
    $GOPATH/src/github.com/go-critic/go-critic/lint/nestingReduce_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/switchTrue_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/defaultCaseOrder_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/lint_private.go:20:25: empty map: use make(map[K]V)
    $GOPATH/src/github.com/go-critic/go-critic/lint/nestingReduce_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/switchTrue_checker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/expr_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/file_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/func_decl_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/local_comment_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/local_expr_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/stmt_list_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/stmt_walker.go:3:1: unit import: wrap single-package import spec into parenthesis
    $GOPATH/src/github.com/go-critic/go-critic/lint/internal/astwalk/visitor.go:3:1: unit import: wrap single-package import spec into parenthesis
    

    For example, lint_private.go:20:25: empty map: use make(map[K]V) reported twice there.

  • Handle types that are not defined inside checked files

    Handle types that are not defined inside checked files

    With the current approach, typeof functions can't return proper types for types imported from the other packages.

    This leads to incomplete type info which in turn makes go-consistent report fewer warnings than it should.

  • Check scope constraints

    Check scope constraints

    Some checks need to be constrained to the function body. See #4 for example. It's illegal to use := outside of the function, so it should not be applied to every var decl.

  • arg list slice doesn't detect all cases

    arg list slice doesn't detect all cases

    Found only 3:

    ./heatmap/add_profile_test.go:399:13: arg list parens: align `)` to a same line with last argument
    ./heatmap/add_profile_test.go:436:13: arg list parens: align `)` to a same line with last argument
    ./heatmap/add_profile_test.go:455:13: arg list parens: align `)` to a same line with last argument
    

    File: https://github.com/quasilyte/perf-heatmap/blob/ce3b3825d8ed89d48c5d5af532c107a450d450bc/heatmap/add_profile_test.go

  • extend empty slice

    extend empty slice

    I see the empty slice section https://github.com/quasilyte/go-consistent#empty-map

    does it make sense to include a var initialisation too? eg

    	a := make([]int, 0)
    	b := []int{}
    	var c []int
    

    https://play.golang.org/p/oI0oilKpgg7

  • Module rename has broken indirectly golangci-lint

    Module rename has broken indirectly golangci-lint

    Your latest commit s/Quasilyte/quasilyte might have broken projects that reference indirectly (maybe even directly, not sure) go-consistent since go mod is case-sensitive and checks the paths (see this issue).

    I am not sure if this is the right place to report it, but since it is the source of the error, I just wanted to warn you in case it is an unexpected side effect. The dependency chain is golangci-lint -> go-critic -> go-consistent.

    To reproduce:

    GO111MODULE=on go get -u github.com/golangci/golangci-lint/cmd/golangci-lint@master              
    go: finding github.com/golangci/golangci-lint/cmd/golangci-lint master                                                                      
    go: finding github.com/golangci/golangci-lint/cmd master                                                                                    
    go: finding github.com/golangci/golangci-lint master                                                                                        
    go: finding github.com/golangci/goconst latest
    ...
     go: finding github.com/golangci/unconvert latest
    go: github.com/Quasilyte/[email protected]: parsing go.mod: unexpected module path "github.com/quasilyte/go-consistent"
    go: finding github.com/logrusorgru/aurora latest
    go: finding gopkg.in/tomb.v1 latest
    go: finding github.com/StackExchange/wmi latest
    go get: error loading module requirements     
    
  • Add Errformat to ReviewDog

    Add Errformat to ReviewDog

    Currently it seems that Reviewdog doesn't support go-consistent.

    Here is the error that Reviewdog spews out:

    reviewdog: "goconsistent" is not supported. consider to add new errrorformat to https://github.com/haya14busa/errorformat
    

    While it is possible to workaround this by defining a custom error format for Reviewdog, this is error-prone since whenever the output of the tool changes Reviewdog will fail to parse the output. For the same reason I think any non-maintainer that tries to make a PR to Reviewdog for adding error format for go-consistent will run into the same concern.

    I hope the maintainers of go-consistent will consider this!

Analyzer: zapvet is static analysis tool for zap

zapvet zapvet is static analysis tool for zap. fieldtype: fieldtype finds confliction type of field Install You can get zapvet by go install command (

Sep 18, 2022
Analyzer: debugcode finds debug codes

debugcode debugcode finds debug codes. builtinprint: finds calling builtin print or println. commentout: finds a commented out debug code without reas

Aug 16, 2021
gostatement is an analyzer checking for occurrence of `go` statements

gostatement gostatement is an analyzer checking for occurrence of go statements. You may want to use a custom func wrapping the statement utilizing re

Nov 4, 2021
Go-perfguard - A static analyzer with emphasis on performance

perfguard This tool is a work in progress. It's not production-ready yet. perfgu

Dec 28, 2022
The most opinionated Go source code linter for code audit.
The most opinionated Go source code linter for code audit.

go-critic Highly extensible Go source code linter providing checks currently missing from other linters. There is never too much static code analysis.

Jan 6, 2023
octocov is a tool for collecting code metrics (code coverage, code to test ratio and test execution time).

octocov is a tool for collecting code metrics (code coverage, code to test ratio and test execution time).

Jan 9, 2023
Detect non-inclusive language in your source code.
Detect non-inclusive language in your source code.

Detect non-inclusive language in your source code. I stay woke - Erykah Badu Creating an inclusive work environment is imperative to a healthy, suppor

Dec 25, 2022
a simple golang SSA viewer tool use for code analysis or make a linter
a simple golang SSA viewer tool use for code analysis or make a linter

ssaviewer A simple golang SSA viewer tool use for code analysis or make a linter ssa.html generate code modify from src/cmd/compile/internal/ssa/html.

May 17, 2022
A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way

go-gitlab A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way NOTE Release v0.6.0 (released on 25-08-2017) no

Jan 6, 2023
[mirror] This is a linter for Go source code.

Golint is a linter for Go source code. Installation Golint requires a supported release of Go. go get -u golang.org/x/lint/golint To find out where g

Dec 23, 2022
depth is tool to retrieve and visualize Go source code dependency trees.

depth is tool to retrieve and visualize Go source code dependency trees. Install Download the appropriate binary for your platform from the Rele

Dec 30, 2022
Print all source code for a given go package or module.

gosrcs gosrcs is a tool to print all the source code a given go package depends on. The original motivation of this tool is to integrate go builds int

Oct 25, 2021
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language

reviewdog - A code review dog who keeps your codebase healthy. reviewdog provides a way to post review comments to code hosting service, such as GitHu

Jan 2, 2023
A Golang tool that does static analysis, unit testing, code review and generate code quality report.
A Golang tool that does static analysis, unit testing, code review and generate code quality report.

goreporter A Golang tool that does static analysis, unit testing, code review and generate code quality report. This is a tool that concurrently runs

Jan 8, 2023
Sloc, Cloc and Code: scc is a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go
Sloc, Cloc and Code: scc is a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go

Sloc Cloc and Code (scc) A tool similar to cloc, sloccount and tokei. For counting physical the lines of code, blank lines, comment lines, and physica

Jan 4, 2023
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language
🐶 Automated code review tool integrated with any code analysis tools regardless of programming language

reviewdog - A code review dog who keeps your codebase healthy. reviewdog provides a way to post review comments to code hosting service, such as GitHu

Jan 7, 2023
Tool to populate your code with traceable and secure error codes

Essential part of any project, especially customer facing is proper and secure error handling. When error happens and customer reports it, it would be nice to know the context of the error and where it exactly occured.

Sep 28, 2022
🔒🌍 Security scanner for your Terraform code
🔒🌍 Security scanner for your Terraform code

????tfsec uses static analysis of your terraform templates to spot potential security issues.

Dec 30, 2022
Know when GC runs from inside your golang code

gcnotifier gcnotifier provides a way to receive notifications after every run of the garbage collector (GC). Knowing when GC runs is useful to instruc

Dec 26, 2022