GolangCI Updates for June 2018

Denis Isaev
golangci
Published in
4 min readJul 1, 2018

GolangCI.com

Report for a GitHub Pull Request

We’ve made reports for pull requests:

Successful report example

Click on Details link in the pull request status to view this report.

Pull request status with Details link for each of integrations

Report for the pull request with issues looks like this:

Report with found issues example

Golangci-Lint

https://golangci.com uses golangci-lint under the hood to perform a code analysis. We’ve launched it in May 2018. In June we’ve implemented a lot of improvements for golangci-lint.

Support more linters

We’ve added 6 more linters to golangci-lint. Newly added linters are disabled by default: we don’t want to overwhelm existing users by found issues. If you would like to enable them for repo connected to https://golangci.com configure them in the .golangci.yml config file.

Unparam

Unparam linter reports about unused params in functions. We’ve run it on Go source code and found 50 issues. Here we discuss only some of them.

$ golangci-lint run --no-config --disable-all -E unparam --print-linter-name=false

syntax/printer.go:134:50: (*printer).addWhitespace - text is unused
func (p *printer) addWhitespace(kind ctrlSymbol, text string) {
^
ssa/dom_test.go:165:40: benchmarkDominators - size always receives 10000
func benchmarkDominators(b *testing.B, size int, bg blockGen) {
^

Function from the first issue:

By some reason, text variable isn’t used. It’s a good practice to name such variables with _ (blank identifier) if you can’t remove them.

In the second issue we see that unparam detects function having param with the same value (size=10000) on each usage:

$ fgrep -r benchmarkDominators .
./dom_test.go:func BenchmarkDominatorsLinear(b *testing.B) { benchmarkDominators(b, 10000, genLinear) }
./dom_test.go:func BenchmarkDominatorsFwdBack(b *testing.B) { benchmarkDominators(b, 10000, genFwdBack) }
./dom_test.go:func BenchmarkDominatorsManyPred(b *testing.B) { benchmarkDominators(b, 10000, genManyPred) }
./dom_test.go:func BenchmarkDominatorsMaxPred(b *testing.B) { benchmarkDominators(b, 10000, genMaxPred) }
./dom_test.go:func BenchmarkDominatorsMaxPredVal(b *testing.B) { benchmarkDominators(b, 10000, genMaxPredValue) }
./dom_test.go:func benchmarkDominators(b *testing.B, size int, bg blockGen) {

Unparam can be configured via .golangci.yml: this config file is used by https://golangci.com and by golangci-lint locally. Unparam has 2 settings: callgraph construction algorithm and whether to check exported functions. You can find documentation to them in example config file.

Misspell

Misspell linter corrects commonly misspelled English words in comments. Unlike unparam, misspell is a fast linter: it uses only AST and doesn’t need type information. We’ve run it on the Hugo repo:

$ time golangci-lint run --no-config --disable-all -E misspell --print-linter-name=falseconfig/services/servicesConfig.go:60:20: `compability` is a misspelling of `compatibility`
// Keep backwards compability.
^
helpers/language.go:49:24: `referenece` is a misspelling of `reference`
// absolute directory referenece. It is what we get.
^

By default misspell uses a neutral variety of English in a dictionary. You can configure it to use US or UK preferences. Setting locale to the US will correct the British spelling of ‘colour’ to ‘color’.

Prealloc

Prealloc finds slice declarations that could potentially be preallocated. We don’t encourage premature optimization but in some circumstances, this linter can be helpful for performance optimization. Example of the found issue in Go compiler toolchain:

Variable absOfFiles can be preallocated:

absOfFiles := make([]string, 0, len(ofiles))

But we’re not sure whether this optimization has an effect on the speed of compiler.

As well as other linters prealloc has some config options to tune.

Nakedret

Nakedret reports naked returns in long functions. Linter disallows usage of naked returns in functions greater than the specified length in lines. The idea is that long functions with naked returns are too complex to read: the reader must scroll up to function beginning to find out which variables are returned.

You can configure minimum function length to trigger the warning, by default it’s 30 lines. We’ve increased a default limit of nakedret from 5 to 30 lines in golangci-lint.

For example, nakedret warns about the naked return in this function in Beego:

lll

lll (line length linter) reports long lines. Default line length limit is 120 characters.

Depguard

Depguard checks if package imports are in a list of acceptable packages.

We use this linter in the golangci-lint project to enforce proper logging: everywhere we must use logger object and don’t use global logging. In config file we disallow usage of logrus:

And only in the logger package we allow it:

Features in golangci-lint

Except for the above, we’ve also supported:

  1. Smart generated files detection: we don’t use the recommended way to detect such files, because a lot of tools don’t follow recommended convention. Instead, we’ve researched a lot of autogenerated file formats and implemented an algorithm to detect all of them.
  2. Full //nolint support. Nolint comments can be used interchangeably with gometalinter.
  3. Skip files and dirs options:
$ golangci-lint run -h | fgrep skip
--skip-dirs strings Regexps of directories to skip
--skip-files strings Regexps of files to skip

See .golangci.example.yml for details.

4. Checkstyle output format: it can be helpful for CI integrations.

Feel free to create issues for any ideas, suggestions or bugs in golangci.com (issue tracker) or golangci-lint (issue tracker).

--

--