🔥 ~6x faster, stricter, configurable, extensible, and beautiful drop-in replacement for golint

Overview

Build Status

revive

Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. Revive provides a framework for development of custom rules, and lets you define a strict preset for enhancing your development & code review processes.


Logo by Georgi Serev

Here's how revive is different from golint:

  • Allows to enable or disable rules using a configuration file.
  • Allows to configure the linting rules with a TOML file.
  • 2x faster running the same rules as golint.
  • Provides functionality for disabling a specific rule or the entire linter for a file or a range of lines.
    • golint allows this only for generated files.
  • Optional type checking. Most rules in golint do not require type checking. If you disable them in the config file, revive will run over 6x faster than golint.
  • Provides multiple formatters which let us customize the output.
  • Allows to customize the return code for the entire linter or based on the failure of only some rules.
  • Everyone can extend it easily with custom rules or formatters.
  • Revive provides more rules compared to golint.

Who uses Revive

  • tidb - TiDB is a distributed HTAP database compatible with the MySQL protocol
  • grafana - The tool for beautiful monitoring and metric analytics & dashboards for Graphite, InfluxDB & Prometheus & More
  • etcd - Distributed reliable key-value store for the most critical data of a distributed system
  • ferret - Declarative web scraping
  • gopass - The slightly more awesome standard unix password manager for teams
  • gitea - Git with a cup of tea, painless self-hosted git service
  • excelize - Go library for reading and writing Microsoft Excel™ (XLSX) files
  • aurora - aurora is a web-based Beanstalk queue server console written in Go
  • soar - SQL Optimizer And Rewriter
  • gorush - A push notification server written in Go (Golang)a
  • dry - dry - A Docker manager for the terminal.
  • go-echarts - The adorable charts library for Golang
  • reviewdog - Automated code review tool integrated with any code analysis tools regardless of programming language
  • rudder-server - Privacy and Security focused Segment-alternative, in Golang and React.
  • sklearn - A partial port of scikit-learn written in Go.
  • protoc-gen-doc - Documentation generator plugin for Google Protocol Buffers.
  • llvm - Library for interacting with LLVM IR in pure Go.
  • jenkins-library - Jenkins shared library for Continuous Delivery pipelines by SAP.
  • pd - Placement driver for TiKV.
  • shellhub - ShellHub enables teams to easily access any Linux device behind firewall and NAT.
  • lorawan-stack - The Things Network Stack for LoRaWAN V3
  • gin-jwt - This is a JWT middleware for Gin framework.
  • gofight - Testing API Handler written in Golang.
  • Beaver - A Real Time Messaging Server.
  • ggz - An URL shortener service written in Golang
  • Codeac.io - Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt.

Open a PR to add your project.

Usage

Since the default behavior of revive is compatible with golint, without providing any additional flags, the only difference you'd notice is faster execution.

revive supports a -config flag whose value should correspond to a TOML file describing which rules to use for revive's linting. If not provided, revive will try to use a global config file (assumed to be located at $HOME/revive.toml). Otherwise, if no configuration TOML file is found then revive uses a built-in set of default linting rules.

Bazel

If you want to use revive with Bazel, take a look at the rules that Atlassian maintains.

Text Editors

let g:ale_linters = {
\   'go': ['revive'],
\}

GitHub Actions

Continuous Integration

Codeac.io - Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt. Check your pull-requests with revive automatically. (free for open-source projects)

Installation

go get -u github.com/mgechev/revive

Command Line Flags

revive accepts three command line parameters:

  • -config [PATH] - path to config file in TOML format, defaults to $HOME/revive.toml if present.

  • -exclude [PATTERN] - pattern for files/directories/packages to be excluded for linting. You can specify the files you want to exclude for linting either as package name (i.e. github.com/mgechev/revive), list them as individual files (i.e. file.go), directories (i.e. ./foo/...), or any combination of the three.

  • -formatter [NAME] - formatter to be used for the output. The currently available formatters are:

    • default - will output the failures the same way that golint does.
    • json - outputs the failures in JSON format.
    • ndjson - outputs the failures as stream in newline delimited JSON (NDJSON) format.
    • friendly - outputs the failures when found. Shows summary of all the failures.
    • stylish - formats the failures in a table. Keep in mind that it doesn't stream the output so it might be perceived as slower compared to others.
    • checkstyle - outputs the failures in XML format compatible with that of Java's Checkstyle.

Sample Invocations

revive -config revive.toml -exclude file1.go -exclude file2.go -formatter friendly github.com/mgechev/revive package/...
  • The command above will use the configuration from revive.toml
  • revive will ignore file1.go and file2.go
  • The output will be formatted with the friendly formatter
  • The linter will analyze github.com/mgechev/revive and the files in package

Comment Directives

Using comments, you can disable the linter for the entire file or only range of lines:

//revive:disable

func Public() {}
//revive:enable

The snippet above, will disable revive between the revive:disable and revive:enable comments. If you skip revive:enable, the linter will be disabled for the rest of the file.

With revive:disable-next-line and revive:disable-line you can disable revive on a particular code line.

You can do the same on a rule level. In case you want to disable only a particular rule, you can use:

//revive:disable:unexported-return
func Public() private {
  return private
}
//revive:enable:unexported-return

This way, revive will not warn you for that you're returning an object of an unexported type, from an exported function.

You can document why you disable the linter by adding a trailing text in the directive, for example

//revive:disable Until the code is stable
//revive:disable:cyclomatic High complexity score but easy to understand

You can also configure revive to enforce documenting linter disabling directives by adding

[directive.specify-disable-reason]

in the configuration. You can set the severity (defaults to warning) of the violation of this directive

[directive.specify-disable-reason]
    severity = "error"

Configuration

revive can be configured with a TOML file. Here's a sample configuration with explanation for the individual properties:

# When set to false, ignores files with "GENERATED" header, similar to golint
ignoreGeneratedHeader = true

# Sets the default severity to "warning"
severity = "warning"

# Sets the default failure confidence. This means that linting errors
# with less than 0.8 confidence will be ignored.
confidence = 0.8

# Sets the error code for failures with severity "error"
errorCode = 0

# Sets the error code for failures with severity "warning"
warningCode = 0

# Configuration of the `cyclomatic` rule. Here we specify that
# the rule should fail if it detects code with higher complexity than 10.
[rule.cyclomatic]
  arguments = [10]

# Sets the severity of the `package-comments` rule to "error".
[rule.package-comments]
  severity = "error"

Default Configuration

The default configuration of revive can be found at defaults.toml. This will enable all rules available in golint and use their default configuration (i.e. the way they are hardcoded in golint).

revive -config defaults.toml github.com/mgechev/revive

This will use the configuration file defaults.toml, the default formatter, and will run linting over the github.com/mgechev/revive package.

Custom Configuration

revive -config config.toml -formatter friendly github.com/mgechev/revive

This will use config.toml, the friendly formatter, and will run linting over the github.com/mgechev/revive package.

Recommended Configuration

The following snippet contains the recommended revive configuration that you can use in your project:

ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0

[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
[rule.redefines-builtin-id]

Available Rules

List of all available rules. The rules ported from golint are left unchanged and indicated in the golint column.

Name Config Description golint Typed
context-keys-type n/a Disallows the usage of basic types in context.WithValue. yes yes
time-naming n/a Conventions around the naming of time variables. yes yes
var-declaration n/a Reduces redundancies around variable declaration. yes yes
unexported-return n/a Warns when a public return is from unexported type. yes yes
errorf n/a Should replace errors.New(fmt.Sprintf()) with fmt.Errorf() yes yes
blank-imports n/a Disallows blank imports yes no
context-as-argument n/a context.Context should be the first argument of a function. yes no
dot-imports n/a Forbids . imports. yes no
error-return n/a The error return parameter should be last. yes no
error-strings n/a Conventions around error strings. yes no
error-naming n/a Naming of error variables. yes no
exported n/a Naming and commenting conventions on exported symbols. yes no
if-return n/a Redundant if when returning an error. yes no
increment-decrement n/a Use i++ and i-- instead of i += 1 and i -= 1. yes no
var-naming whitelist & blacklist of initialisms Naming rules. yes no
package-comments n/a Package commenting conventions. yes no
range n/a Prevents redundant variables when iterating over a collection. yes no
receiver-naming n/a Conventions around the naming of receivers. yes no
indent-error-flow n/a Prevents redundant else statements. yes no
argument-limit int Specifies the maximum number of arguments a function can receive no no
cyclomatic int Sets restriction for maximum Cyclomatic complexity. no no
max-public-structs int The maximum number of public structs in a file. no no
file-header string Header which each file should have. no no
empty-block n/a Warns on empty code blocks no yes
superfluous-else n/a Prevents redundant else statements (extends indent-error-flow) no no
confusing-naming n/a Warns on methods with names that differ only by capitalization no no
get-return n/a Warns on getters that do not yield any result no no
modifies-parameter n/a Warns on assignments to function parameters no no
confusing-results n/a Suggests to name potentially confusing function results no no
deep-exit n/a Looks for program exits in funcs other than main() or init() no no
unused-parameter n/a Suggests to rename or remove unused function parameters no no
unreachable-code n/a Warns on unreachable code no no
add-constant map Suggests using constant for magic numbers and string literals no no
flag-parameter n/a Warns on boolean parameters that create a control coupling no no
unnecessary-stmt n/a Suggests removing or simplifying unnecessary statements no no
struct-tag n/a Checks common struct tags like json,xml,yaml no no
modifies-value-receiver n/a Warns on assignments to value-passed method receivers no yes
constant-logical-expr n/a Warns on constant logical expressions no no
bool-literal-in-expr n/a Suggests removing Boolean literals from logic expressions no no
redefines-builtin-id n/a Warns on redefinitions of builtin identifiers no no
function-result-limit int Specifies the maximum number of results a function can return no no
imports-blacklist []string Disallows importing the specified packages no no
range-val-in-closure n/a Warns if range value is used in a closure dispatched as goroutine no no
range-val-address n/a Warns if address of range value is used dangerously no no
waitgroup-by-value n/a Warns on functions taking sync.WaitGroup as a by-value parameter no no
atomic n/a Check for common mistaken usages of the sync/atomic package no no
empty-lines n/a Warns when there are heading or trailing newlines in a block no no
line-length-limit int Specifies the maximum number of characters in a line no no
call-to-gc n/a Warns on explicit call to the garbage collector no no
duplicated-imports n/a Looks for packages that are imported two or more times no no
import-shadowing n/a Spots identifiers that shadow an import no no
bare-return n/a Warns on bare returns no no
unused-receiver n/a Suggests to rename or remove unused method receivers no no
unhandled-error []string Warns on unhandled errors returned by funcion calls no yes
cognitive-complexity int Sets restriction for maximum Cognitive complexity. no no
string-of-int n/a Warns on suspicious casts from int to string no yes
early-return n/a Spots if-then-else statements that can be refactored to simplify code reading no no
unconditional-recursion n/a Warns on function calls that will lead to (direct) infinite recursion no no
identical-branches n/a Spots if-then-else statements with identical then and else branches no no
defer map Warns on some defer gotchas no no
unexported-naming n/a Warns on wrongly named un-exported symbols no no
function-length n/a Warns on functions exceeding the statements or lines max no no

Configurable rules

Here you can find how you can configure some of the existing rules:

var-naming

This rule accepts two slices of strings, a whitelist and a blacklist of initialisms. By default the rule behaves exactly as the alternative in golint but optionally, you can relax it (see golint/lint/issues/89)

[rule.var-naming]
  arguments = [["ID"], ["VM"]]

This way, revive will not warn for identifier called customId but will warn that customVm should be called customVM.

Available Formatters

This section lists all the available formatters and provides a screenshot for each one.

Friendly

Friendly formatter

Stylish

Stylish formatter

Default

The default formatter produces the same output as golint.

Default formatter

Plain

The plain formatter produces the same output as the default formatter and appends URL to the rule description.

Plain formatter

Unix

The unix formatter produces the same output as the default formatter but surrounds the rules in [].

Unix formatter

Extensibility

The tool can be extended with custom rules or formatters. This section contains additional information on how to implement such.

To extend the linter with a custom rule or a formatter you'll have to push it to this repository or fork it. This is due to the limited -buildmode=plugin support which works only on Linux (with known issues).

Custom Rule

Each rule needs to implement the lint.Rule interface:

type Rule interface {
	Name() string
	Apply(*File, Arguments) []Failure
}

The Arguments type is an alias of the type []interface{}. The arguments of the rule are passed from the configuration file.

Example

Let's suppose we have developed a rule called BanStructNameRule which disallow us to name a structure with given identifier. We can set the banned identifier by using the TOML configuration file:

[rule.ban-struct-name]
  arguments = ["Foo"]

With the snippet above we:

  • Enable the rule with name ban-struct-name. The Name() method of our rule should return a string which matches ban-struct-name.
  • Configure the rule with the argument Foo. The list of arguments will be passed to Apply(*File, Arguments) together with the target file we're linting currently.

A sample rule implementation can be found here.

Custom Formatter

Each formatter needs to implement the following interface:

type Formatter interface {
	Format(<-chan Failure, Config) (string, error)
	Name() string
}

The Format method accepts a channel of Failure instances and the configuration of the enabled rules. The Name() method should return a string different from the names of the already existing rules. This string is used when specifying the formatter when invoking the revive CLI tool.

For a sample formatter, take a look at this file.

Speed Comparison

Compared to golint, revive performs better because it lints the files for each individual rule into a separate goroutine. Here's a basic performance benchmark on MacBook Pro Early 2013 run on kubernetes:

golint

time golint kubernetes/... > /dev/null

real    0m54.837s
user    0m57.844s
sys     0m9.146s

revive

# no type checking
time revive -config untyped.toml kubernetes/... > /dev/null

real    0m8.471s
user    0m40.721s
sys     0m3.262s

Keep in mind that if you use rules which require type checking, the performance may drop to 2x faster than golint:

# type checking enabled
time revive kubernetes/... > /dev/null

real    0m26.211s
user    2m6.708s
sys     0m17.192s

Currently, type checking is enabled by default. If you want to run the linter without type checking, remove all typed rules from the configuration file.

Overriding colorization detection

By default, revive determines whether or not to colorize its output based on whether it's connected to a TTY or not. This works for most use cases, but may not behave as expected if you use revive in a pipeline of commands, where STDOUT is being piped to another command.

To force colorization, add REVIVE_FORCE_COLOR=1 to the environment you're running in. For example:

REVIVE_FORCE_COLOR=1 revive -formatter friendly ./... | tee revive.log

Contributors

mgechev chavacava renovate-bot xuri dshemin gsamokovarov
mgechev chavacava renovate-bot xuri dshemin gsamokovarov
morphy2k tymonx markelog tamird mapreal19 Clivern
morphy2k tymonx markelog tamird mapreal19 Clivern
AragurDEV bernhardreisenberger yangdiangzb quasilyte jamesmaidment johnrichardrinehart
AragurDEV bernhardreisenberger yangdiangzb quasilyte jamesmaidment johnrichardrinehart
mathieu-aubin michalhisim pa-m paul-at-start liaoishere ridvansumset
mathieu-aubin michalhisim pa-m paul-at-start liaoishere ridvansumset
Jarema vkrol haya14busa
Jarema vkrol haya14busa

License

MIT

Issues
  • Add SemVer releases

    Add SemVer releases

    Is your feature request related to a problem? Please describe. The idiomatic way to create software is to publish releases when required (fix, new feature, api break...). There is currently no versioning for revive.

    Describe the solution you'd like

    I would like to suggest https://github.com/astrocorp42/rocket to automate GitHub releases. Thus We can automate releasing and binaries publishing. Furthermore it would enable automated Docker publishing which is great for users of services like drone.io.

    It would requires a Makefile (for example: https://github.com/astrocorp42/rocket/blob/master/Makefile), to build revive.

    Describe alternatives you've considered https://github.com/goreleaser/goreleaser but it mix too many things (build + publishing).

    opened by skerkour 18
  • Package-wide analysis

    Package-wide analysis

    Hi @mgechev, I would love to develop some rules that need package-wide analysis (e.g. unused-function) but I do not see how to implement the analysis pattern required by these kind of rules.

    I've developed one package-wide rule (confusing-naming). A raw description of the rule is: create a global registry of names, and for each linted file: a) enrich that list, and b) check new names vs those in the list. Because two names are similar (confusing) no matter the order in which we find them, checks are independent of: the order in which package files are analyzed, and the global progress of the analysis.

    That is not the case of, for example, unused-function: checks can be done only when all files in the package were analyzed (it is not possible to flag a function as unused until all files of the package have been analyzed). These kind of rules need something like a reduce phase after been applied to all package's files.

    My understanding is that rules are applied as follows:

    for each file in the package
      go { 
        for each rule
          rule.Apply(file)
        send failures
      }
    

    Files are concurrently analyzed (and that is good :+1: ), thus at rule-level it is impossible to have information of the global (package-level) progress of the analysis.

    Is my understanding wrong? Do you see how to implement a rule like unused-function without modifying the linter logic?

    opened by chavacava 17
  • panic: unable to type check

    panic: unable to type check

    Describe the bug We've seen a transient panic in revive in our CI job (it did not occur when the job was retried).

    revive -exclude vendor/... -formatter friendly -config .revive.toml ./...
     panic: unable to type check [redacted file A]:[redacted file A]:3:8: could not import [redacted pkg B] (can't find import: [redacted pkg B])
     goroutine 123 [running]:
     github.com/mgechev/revive/rule.(*EmptyBlockRule).Apply(0x9e06d0, 0xc000f70b80, 0x0, 0x0, 0x0, 0x9e06d0, 0x0, 0x0)
        /go/src/github.com/mgechev/revive/rule/empty-block.go:23 +0x20e
     github.com/mgechev/revive/lint.(*File).lint(0xc000f70b80, 0xc0003b6800, 0x27, 0x40, 0x0, 0x3fd0000000000000, 0xc000030a40, 0x7, 0xc00007dfb0, 0x1, ...)
        /go/src/github.com/mgechev/revive/lint/file.go:108 +0x3b6
     github.com/mgechev/revive/lint.(*Package).lint.func1(0xc0003b6800, 0x27, 0x40, 0x0, 0x3fd0000000000000, 0xc000030a40, 0x7, 0xc00007dfb0, 0x1, 0x1, ...)
        /go/src/github.com/mgechev/revive/lint/package.go:173 +0xb5
     created by github.com/mgechev/revive/lint.(*Package).lint
        /go/src/github.com/mgechev/revive/lint/package.go:172 +0x179
    

    https://github.com/mgechev/revive/blob/1da965b65f8a0e3aa83cd9d6d38153a32f308960/rule/empty-block.go#L23

    To Reproduce

    I couldn't reproduce the issue - it worked when I retried the job. Could it have been caused by some network issue when getting the package from our internal git repo?

    Expected behavior Expected to see better error message describing why it couldn't find the import.

    Desktop (please complete the following information):

    • Version of Go: 1.14.2
    opened by martin-sucha 16
  • panic: assertion failed [recovered]

    panic: assertion failed [recovered]

    Describe the bug revive panics.

    To Reproduce Steps to reproduce the behavior:

    1. I updated revive go get -u github.com/mgechev/revive
    2. I run it with the following flags & configuration file:
    # flags
    
    ~/.gotools/bin/revive -config=$HOME/.revive.toml ./...
    
    # config file
    ignoreGeneratedHeader = false
    severity = "warning"
    confidence = 0.8
    errorCode = 0
    warningCode = 0
    
    [rule.blank-imports]
    [rule.context-as-argument]
    [rule.context-keys-type]
    [rule.dot-imports]
    [rule.error-return]
    [rule.error-strings]
    [rule.error-naming]
    #[rule.exported]
    [rule.if-return]
    [rule.increment-decrement]
    #[rule.var-naming]
    [rule.var-declaration]
    [rule.package-comments]
    [rule.range]
    #[rule.receiver-naming]
    [rule.time-naming]
    [rule.unexported-return]
    [rule.indent-error-flow]
    [rule.errorf]
    

    Expected behavior No panic.

    Logs

    [...]
    vendor/github.com/apache/thrift/lib/go/thrift/server_socket.go:92:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
    panic: assertion failed [recovered]
    	panic: assertion failed
    
    goroutine 1315 [running]:
    go/types.(*Checker).handleBailout(0xc0005b6870, 0xc008cab800)
    	/usr/local/go/src/go/types/check.go:236 +0x98
    panic(0x12b3600, 0x1370730)
    	/usr/local/go/src/runtime/panic.go:513 +0x1b9
    go/types.assert(...)
    	/usr/local/go/src/go/types/errors.go:18
    go/types.(*Checker).recordTypeAndValue(0xc0005b6870, 0x0, 0x0, 0x3, 0x1374960, 0xc02fead160, 0x0, 0x0)
    	/usr/local/go/src/go/types/check.go:281 +0x279
    go/types.(*Checker).exprInternal(0xc0005b6870, 0xc02fed4e00, 0x13755a0, 0xc00a1ca800, 0x1374960, 0xc02fead160, 0x100b3c3)
    	/usr/local/go/src/go/types/expr.go:1164 +0x17c4
    go/types.(*Checker).rawExpr(0xc0005b6870, 0xc02fed4e00, 0x13755a0, 0xc00a1ca800, 0x1374960, 0xc02fead160, 0x100ba38)
    	/usr/local/go/src/go/types/expr.go:969 +0x81
    go/types.(*Checker).exprWithHint(0xc0005b6870, 0xc02fed4e00, 0x13755a0, 0xc00a1ca800, 0x1374960, 0xc02fead160)
    	/usr/local/go/src/go/types/expr.go:1597 +0x73
    go/types.(*Checker).indexedElts(0xc0005b6870, 0xc005257a00, 0x1c, 0x20, 0x1374960, 0xc02fead160, 0xffffffffffffffff, 0x1374960)
    	/usr/local/go/src/go/types/expr.go:939 +0x1e2
    go/types.(*Checker).exprInternal(0xc0005b6870, 0xc02fed4d00, 0x13755a0, 0xc00a1cb600, 0x0, 0x0, 0x101e728)
    	/usr/local/go/src/go/types/expr.go:1158 +0x1759
    go/types.(*Checker).rawExpr(0xc0005b6870, 0xc02fed4d00, 0x13755a0, 0xc00a1cb600, 0x0, 0x0, 0xc00028cd80)
    	/usr/local/go/src/go/types/expr.go:969 +0x81
    go/types.(*Checker).multiExpr(0xc0005b6870, 0xc02fed4d00, 0x13755a0, 0xc00a1cb600)
    	/usr/local/go/src/go/types/expr.go:1575 +0x58
    go/types.(*Checker).expr(0xc0005b6870, 0xc02fed4d00, 0x13755a0, 0xc00a1cb600)
    	/usr/local/go/src/go/types/expr.go:1569 +0x49
    go/types.(*Checker).varDecl(0xc0005b6870, 0xc011a03180, 0xc01ca5d008, 0x1, 0x1, 0x0, 0x0, 0x13755a0, 0xc00a1cb600)
    	/usr/local/go/src/go/types/decl.go:425 +0x1b7
    go/types.(*Checker).objDecl(0xc0005b6870, 0x1378080, 0xc011a03180, 0x0, 0xc008cab700, 0x0, 0x8)
    	/usr/local/go/src/go/types/decl.go:244 +0x83c
    go/types.(*Checker).packageObjects(0xc0005b6870)
    	/usr/local/go/src/go/types/resolver.go:542 +0x26f
    go/types.(*Checker).checkFiles(0xc0005b6870, 0xc00d253000, 0x1e, 0x20, 0x0, 0x0)
    	/usr/local/go/src/go/types/check.go:250 +0xa5
    go/types.(*Checker).Files(0xc0005b6870, 0xc00d253000, 0x1e, 0x20, 0xc00d0c47d0, 0xc00a68f030)
    	/usr/local/go/src/go/types/check.go:241 +0x49
    go/types.(*Config).Check(0xc00d0c68c0, 0xc010c98d17, 0x5, 0xc0021ccd40, 0xc00d253000, 0x1e, 0x20, 0xc00d0c4730, 0x101e728, 0xc0094dd940, ...)
    	/usr/local/go/src/go/types/api.go:351 +0x11a
    github.com/mgechev/revive/lint.(*Package).TypeCheck(0xc0021ccd80, 0xc0094dd940, 0xc011429880)
    	/Users/sandbox/.gotools/src/github.com/mgechev/revive/lint/package.go:80 +0x351
    github.com/mgechev/revive/rule.(*TimeNamingRule).Apply(0x15813c0, 0xc01240f740, 0x0, 0x0, 0x0, 0x1581568, 0x0, 0x0)
    	/Users/sandbox/.gotools/src/github.com/mgechev/revive/rule/time-naming.go:25 +0xb6
    github.com/mgechev/revive/lint.(*File).lint(0xc01240f740, 0xc00019e700, 0x10, 0x10, 0x0, 0x3fe999999999999a, 0xc0000146e0, 0x7, 0xc00000f710, 0x0, ...)
    	/Users/sandbox/.gotools/src/github.com/mgechev/revive/lint/file.go:100 +0x36a
    github.com/mgechev/revive/lint.(*Package).lint.func1(0xc00019e700, 0x10, 0x10, 0x0, 0x3fe999999999999a, 0xc0000146e0, 0x7, 0xc00000f710, 0x0, 0x0, ...)
    	/Users/sandbox/.gotools/src/github.com/mgechev/revive/lint/package.go:157 +0x94
    created by github.com/mgechev/revive/lint.(*Package).lint
    	/Users/sandbox/.gotools/src/github.com/mgechev/revive/lint/package.go:156 +0x173
    

    Desktop (please complete the following information):

    • OS: macOS 10.13
    • Go 1.11

    Additional context The repository tested is https://github.com/pingcap/tidb.

    opened by l2dy 14
  • Conf reason rule disabling

    Conf reason rule disabling

    Closes #190

    opened by chavacava 13
  • new rule: nested-structs

    new rule: nested-structs

    Please, describe in details what's your motivation for this PR

    Nested structs are awful to look at and I want to disallow them entirely in my projects.

    Did you add tests?

    Yes.

    Does your code follows the coding style of the rest of the repository?

    Yes.

    Does the Travis build passes?

    TBD

    Closes #529

    opened by rdeusser 11
  • Expose the ability to enable all rules

    Expose the ability to enable all rules

    Hello, and thanks for the linter. I have a feature request.

    Right now, it appears that the only way that users can enable all rules and disable one rule is to manually specify every single existing rule into the config except for the one specific one that they don't want.

    This is tedious, and not very future proof. Meaning that when you guys add a new useful rule, I don't want to have to manually do research and find out which specific new rule that you added, and then manually add that new rule to my config in order to stay up-to-date. I just want to upgrade my version of golangci-lint and automatically get the latest and greatest linting without having to change my config.

    As an analogy, golangci-lint allows this kind of workflow with the following YML config:

    linters:
      enable-all: true
      disable:
        # These linters are deprecated
        - interfacer
        - maligned
        - scopelint
    
    feature request 
    opened by Zamiell 11
  • Rules documentation

    Rules documentation

    Is your feature request related to a problem? Please describe. Some warning/error messages generated by rules are not enough to clearly understand what is wrong in the code or, more important, why.

    Linters are a good source of knowledge for beginners, we can learn from reported warnings/errors.

    For example, a warning use i++ instead of i += 1 does not provide any clue about why we should prefer i++

    Describe the solution you'd like Add a document that describes the spirit of rules. The document may also describe rule configuration details.

    Describe alternatives you've considered

    Java's FindBugs checks documentation is a good example.

    opened by chavacava 11
  • Using golangci-lint is there a way to disable a single revive's rule?

    Using golangci-lint is there a way to disable a single revive's rule?

    I'm using golangci-lint 1.40.1.

    Is there a way to disable a single revive's rule?

    Such as:

    linters-settings:
      revive:
        rules:
          - name: exported
            deactivate: true
    

    This doesn't work right now.

    opened by frederikhors 10
  • extract package comments form and exported comments form

    extract package comments form and exported comments form

    I do not like when linter tells me how to write my documentation

    Closes #105

    opened by ademenev 9
  • Allow `*testing.T` before `context.Context` in the context parameter check

    Allow `*testing.T` before `context.Context` in the context parameter check

    This issue mirrors the upstream one here, which ended up stalling out due to upstream abandoning golint.

    The specific case I'm referring to looks like so:

    func TestFoo(t *testing.T) {
      ctx, cancel := context.WithCancel(context.Backgrdoun())
      defer cancel()
      t.Run("subtest1", func(t *tesitng.T) {
        ctx, cancel := context.WithCancel(ctx)
        fooSubtest1(t, ctx)
      })
    }
    
    func fooSubtest1(t *testing.T, ctx context.Context) {
      // do things that require a context
    }
    

    Currently, the context-as-argument lint will complain that fooSubtest1 should be written with the signature func(context.Context, *testing.T) instead.

    To me, it's idiomatic for *testing.T to remain the first argument of fooSubtest since it's effectively being curried in. Ideally, if this language supported currying, we'd do something more akin to subtest1 := t.Run("subtest1", fooSubtest1); subtest1(ctx), but without language support for currying, it seems like manually passing through the t first makes more sense.

    So, that leads me to the question for this issue: Should we update revive to allow this? Is there some other hoops we should jump through first?

    I'm happy to provide the code changes necessary to make the current context lint accept this (and have them written up over here in fact.)

    opened by euank 1
  • `unhandled-error ` could not detect unhandled errors of third party package methods

    `unhandled-error ` could not detect unhandled errors of third party package methods

    Describe the bug

    Method TypeCheck() will return error "could not import xxx" if detect third party package. Such as: could not import github.com/hyperledger/fabric/core/chaincode/shim (can't find import: github.com/hyperledger/fabric/core/chaincode/shim)

    When the error emerged, revive could not get enough type information. So revive could not detect unhandled errors of third party package methods and nothing reported.

    package main
    
    import (
    
    	"github.com/hyperledger/fabric/core/chaincode/shim"
    	pb "github.com/hyperledger/fabric/protos/peer"
    )
    
    func (t *SimpleChaincode) insert(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    
    	if len(args) != 2 {
    		return shim.Error("Incorrect number of arguments. Expecting 2")
    	}
    	key := args[0]
    	val := args[1]
    
    	// Unhandled error
    	stub.PutState(key, []byte(val))
    	return shim.Success(nil)
    }
    
    
    bug help wanted hacktoberfest 
    opened by ChenhuaYang 2
  • Dependency Dashboard

    Dependency Dashboard

    This issue provides visibility into Renovate updates and their statuses. Learn more

    This repository currently has no open or pending branches.


    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
  • Extending defaults config

    Extending defaults config

    Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

    I am wondering if there is any way to extend the default rules' configuration. One such situation would be with import-blacklist which is an array formed of two crypto imports by default md5 and sha1, but to which I would like to add another entry. However, I don't want to "override" default values and still have update on best practices if default configurations have to evolve over time.

    Describe the solution you'd like A clear and concise description of what you want to happen.

    I don't have a clear solution in mind other than have a keyword "&default" that would simply use the default provided value if any or raise an error otherwise.

    Example:

    [rule.import-blacklist]
      arguments = ['&default', 'some/new/package']
    

    Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

    Additional context Add any other context or screenshots about the feature request here.

    feature request 
    opened by SamuelCabralCruz 0
  • string-of-int missed a cast that `go vet` caught

    string-of-int missed a cast that `go vet` caught

    The bug

    I just started hooking up revive, and results are very good so far! Many thanks for this project :) When adding the string-of-int check, I toyed around with the equivalent go vet -stringintconv check, and found a discrepancy that seems.... odd.

    Undoing a fix in this commit reproduces it, the shardIDstr := string(shardID) line below is not found:

    ~/gocode/src/github.com/uber/cadence @beb64a7b !1 
    ❯ git diff
    diff --git service/frontend/adminHandler.go service/frontend/adminHandler.go
    index f4168390..179fb4a9 100644
    --- service/frontend/adminHandler.go
    +++ service/frontend/adminHandler.go
    @@ -248,7 +248,7 @@ func (adh *adminHandlerImpl) DescribeWorkflowExecution(
        }
     
        shardID := common.WorkflowIDToHistoryShard(request.Execution.WorkflowID, adh.numberOfHistoryShards)
    -   shardIDstr := string(rune(shardID)) // originally `string(int_shard_id)`, but changing it will change the ring hashing
    +   shardIDstr := string(shardID) // originally `string(int_shard_id)`, but changing it will change the ring hashing
        shardIDForOutput := strconv.Itoa(shardID)
     
        historyHost, err := adh.GetMembershipMonitor().Lookup(common.HistoryServiceName, shardIDstr)
    
    ~/gocode/src/github.com/uber/cadence @beb64a7b !1 
    ❯ make lint | grep string-of-int
    <nothing>
    

    Since the same variable is used in strconv.Itoa(shardID), it's pretty clear that shardID is an int, and this is not a line that should have succeeded. go vet -stringintconv ./... with go 1.15.7 finds it, as further evidence:

    ❯ go vet -stringintconv ./...
    # github.com/uber/cadence/service/frontend
    service/frontend/adminHandler.go:251:16: conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
    

    I'm really not sure where this behavior could be coming from, as the string-of-int code is pretty simple at a glance, and it found all the other instances.
    My suspicion is that there could be some mutating of the AST / type data by other rules, but I don't really know where to start looking for that.

    To Reproduce

    I've tried making a small repro for this, but the same kinds of lines of code + the same config file don't reproduce it... so unfortunately I can only point you to the repo where I encountered this. Thankfully it's open source!

    1. Clone https://github.com/uber/cadence somewhere
    2. git checkout beb64a7b
    3. Make the changes in the diff output above ^, as this commit contains the fixed line
    4. make lint | grep string-of-int should download and build everything necessary automatically. Everything should be isolated / not install a bunch of stuff globally on your machine.
    5. Note that line 251 does not result in a warning.

    Revive's version and related libraries are all pinned by the go.mod, and the config toml and --exclude flags are part of the make lint target (and they will be printed), so this should be easily reproducible.

    Let me know if you have any trouble running those steps, I'd be happy to try to fix it :)

    bug nice to have 
    opened by Groxx 5
  • Indirectly imported types have

    Indirectly imported types have "invalid type"

    If a function returns a type declared in another package, you cannot determine the type in a linter rule. after running TypeCheck() and looking at the entry in TypesInfo.Defs, it has "invalid type".

    A minimal reproduction would look like this:

    a/a.go:

    package a
    
    import "errors"
    
    func Err() error {
        return errors.New("")
    }
    

    example.go:

    package example
    
    import (
        "errors"
    
        "a"
    )
    
    var errInvalidType = a.Err()
    var errValidType = errors.New("")
    

    If you lint this file with a linter rule like the following:

    func (w *lintRule) Visit(node ast.Node) ast.Visitor {
    	n, ok := node.(*ast.GenDecl)
    	if !ok {
    		return w
    	}
    
    	if n.Tok != token.VAR {
    		return w
    	}
    
    	spec := n.Specs[0].(*ast.ValueSpec)
    	id := spec.Names[0]
    
    	obj := w.file.Pkg.TypesInfo.Defs[id]
    	fmt.Printf("%q has type %v\n", id.Name, obj)
    }
    

    You will get this output:

    "errInvalidType" has type var main.errInvalidType invalid type
    "errValidType" has type var main.errValidType error
    

    This seems to be a problem with the importer from golang.org/x/tools/go/gcexportdata. I'm not able to reproduce this when I load the AST tree myself using golang.org/x/tools/go/packages instead.

    feature request 
    opened by jniedrauer 5
  • How to setup rules for camelCase enforcement?

    How to setup rules for camelCase enforcement?

    Describe the solution you'd like Option to enforce camelCase usage for variable and function names.

    feature request 
    opened by mariadb-zdraganov 0
  • Rule specific include and exclude patterns

    Rule specific include and exclude patterns

    Is your feature request related to a problem? Please describe. Similar to #244, and discussed in those comments A family of micro services that are contained in one repository. Some code is specific to individual services, other packages are shared/used for multiple services. To be specific, rules like [rule.exported] could be only enforced on code that is reused across the micro services. To run that rule, and other non-enforced rules, on the entire repository creates a problem of always seeing lint messages. This creates an overhead of needing to scan the listed lint messages to see if they fall into the not-enforced category.

    Describe the solution you'd like Introduce a new config parameter along side arguments. This new argument (patterns? -- I'm sure there's a better name} would be 1 or 2 slices of strings:

    [rule.var-naming]
      arguments = [["ID"], ["VM"]]
      patterns =[["incl*regex1", "incl*regex2"], ["*exclude*regex"]]
    

    The complexity I see is that lint.File struct only knows its name. Being limited to only use the filename in the include/exclude patterns would possibly cause an excessive list of items that would be a maintenance burden as new files are added to particular packages. It might also influence file naming patterns just to support the rule include/exclude regex. As my need is the same as that comment referenced above -- that certain packages have different lint-free expectations. I think this solution would need the lint.File struct to now its full path. Determining more information about the file (full path, Go package) might be an excessive performance cost -- at least something of which to be cognizant.

    Describe alternatives you've considered What if each package had its own TOML configuration file? Similar to .gitignore. Would child directory/package config files overwrite parent level configuration? Would it be necessary to support specifically disabling rules instead of relying on their absence. This solution seems excessive, heavy handed.

    Additional context The use of the go-doc annotations feels unwieldy to solve this problem. My perspective of those is for one-off situations where exceptions are warranted.

    feature request 
    opened by jwmach1 3
  • warn when passing a pointer explicitely and method receiver is not a pointer receiver

    warn when passing a pointer explicitely and method receiver is not a pointer receiver

    Is your feature request related to a problem? Please describe.

    type fnCallsVisitor struct {
    	fnNames []string 
    }
    
    // Notice method receiver is not a pointer receiver "f *fnCallsVisitor".
    // Therefore object is passed as a value and not by reference
    func (f fnCallsVisitor) Visit(node dst.Node) (w dst.Visitor) {
        // f.Names = append(f.Names, node.StringProperty)
        return f
    }
    
    
    func getHelperNames(fn *dst.FuncDecl) []string {
    	fncalls := fnCallsVisitor{}
        // Notice: explicit call to pass pointer
    	dst.Walk(&fncalls, fn)
    }
    

    This is an issue when an API changes underneath you. Making a call to an API, passing the pointer with "&" then later API method changes from pointer receiver to value and there are no warnings.

    Or in my case, using the IDE to implement the interface "dst.Visitor" but IDE generated code didn't use a pointer receiver and not noticing until debugging

    Describe the solution you'd like

    Passing a pointer explicitely (using "&") to a method receiver that is not a pointer receiver should issue a warning because at the very least, the "&" is not necessary or it is indicative of an error.

    This will be a problem and could create false positives. e.g method receiver is "interface{}" and using reflect to manipulate the pointer. If reflection is involved, warning confidence should be reduced.

    Describe alternatives you've considered

    Other than modifying the ast and decorating it with some asserts to ensure it's the same pointer. A lint warning would be better though.

    Additional context

    Thank you for considering this as a rule proposal and feel free to highlight any false positives that may occur that I haven't considered.

    feature request 
    opened by hbt 2
  • Warn on unused variables, functions and methods

    Warn on unused variables, functions and methods

    Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

    Describe the solution you'd like A clear and concise description of what you want to happen.

    Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

    Additional context Add any other context or screenshots about the feature request here.

    enhancement 
    opened by iiinsomnia 4
Releases(v1.1.2)
Owner
Minko Gechev
Working on Angular at Google. Previously co-founder & CTO of Rhyme.com (acquired by Coursera) 🇧🇬🇺🇸
Minko Gechev
🐶 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

reviewdog 4.3k Oct 20, 2021
Run linters from Go code -

Lint - run linters from Go Lint makes it easy to run linters from Go code. This allows lint checks to be part of a regular go build + go test workflow

Surul Software Labs GmbH 66 Oct 5, 2020
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

Ben Boyter 2.8k Oct 16, 2021
Bundle k6 with extensions as fast and easily as possible

xk6bundler xk6bundler is a CLI tool and GitHub Action makes bundle k6 with extensions as fast and easily as possible. Features Build for multiple targ

Iván Szkiba 6 Sep 3, 2021
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

360 Enterprise Security Group, Endpoint Security, inc. 2.9k Oct 17, 2021
A report card for your Go application

Go Report Card A web application that generates a report on the quality of an open source go project. It uses several measures, including gofmt, go ve

GoJP 1.6k Oct 16, 2021
checkstyle for go

go-checkstyle checkstyle is a style check tool like java checkstyle. This tool inspired by java checkstyle, golint. The style refered to some points i

Qiniu Cloud 115 Oct 14, 2021
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.

null 1k Oct 15, 2021
Fast division, modulus and divisibility checks in Go for divisors known only at runtime.

fastdiv Fast division, modulus and divisibility checks for divisors known only at runtime via the method of: "Faster Remainder by Direct Computation:

null 89 Jul 19, 2021
MOVED TO GITLAB

blanket blanket is a tool that helps you catch functions which don't have direct unit tests in your Go packages. Installation go get -u gitlab.com/ver

Jeffrey D. 14 Mar 23, 2020
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

Carlo Alberto Ferraris 162 Oct 10, 2021
A reference for the Go community that covers the fundamentals of writing clean code and discusses concrete refactoring examples specific to Go.

A reference for the Go community that covers the fundamentals of writing clean code and discusses concrete refactoring examples specific to Go.

Lasse Martin Jakobsen 1.9k Oct 19, 2021
The Golang linter that checks that there is no simultaneous return of `nil` error and an invalid value.

nilnil Checks that there is no simultaneous return of nil error and an invalid value. Installation & usage $ go install github.com/Antonboom/[email protected]

Anton Telyshev 3 Sep 28, 2021
Refactoring and code transformation tool for Go.

gopatch is a tool to match and transform Go code. It is meant to aid in refactoring and restyling.

Uber Go 377 Oct 13, 2021
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.

vs 51 Apr 4, 2021
A static code analyzer for annotated TODO comments

todocheck todocheck is a static code analyzer for annotated TODO comments. It let's you create actionable TODOs by annotating them with issues from an

Preslav Mihaylov 357 Oct 18, 2021
apicompat checks recent changes to a Go project for backwards incompatible changes

Introduction apicompat is a tool to check for the introduction of backwards incompatible changes. apicompat: Guarantees that all consumers of a librar

Bradley Falzon 174 Aug 9, 2021
GoKart - Go Security Static Analysis

GoKart is a static analysis tool for Go that finds vulnerabilities using the SSA (single static assignment) form of Go source code.

Praetorian 1.8k Oct 18, 2021