2018-05-27 01:39:22 +02:00
[![Build Status ](https://travis-ci.org/mgechev/revive.svg?branch=master )](https://travis-ci.org/mgechev/revive)
2017-08-28 05:57:46 +02:00
# revive
2018-06-01 20:28:50 +02:00
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**.
2017-08-28 06:05:02 +02:00
2017-08-28 06:00:20 +02:00
< p align = "center" >
2018-05-30 22:44:18 +02:00
< img src = "./assets/logo.png" alt = "" width = "300" >
< br >
Logo by < a href = "https://github.com/hawkgs" > Georgi Serev< / a >
2017-08-28 06:00:20 +02:00
< / p >
2017-08-28 05:59:53 +02:00
2018-02-04 23:42:05 +02:00
Here's how `revive` is different from `golint` :
2018-06-08 19:28:17 +02:00
- Allows us to enable or disable rules using a configuration file.
- Allows us 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 us 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` .
2018-02-04 23:42:05 +02:00
2018-05-30 22:42:28 +02:00
< p align = "center" >
2018-05-30 22:44:18 +02:00
< img src = "./assets/demo.svg" alt = "" width = "700" >
2018-05-30 22:42:28 +02:00
< / p >
2018-06-08 19:28:17 +02:00
<!-- TOC -->
- [revive ](#revive )
2018-07-08 00:15:12 +02:00
- [Usage ](#usage )
- [Text Editors ](#text-editors )
- [Installation ](#installation )
- [Command Line Flags ](#command-line-flags )
- [Sample Invocations ](#sample-invocations )
- [Comment Annotations ](#comment-annotations )
- [Configuration ](#configuration )
- [Default Configuration ](#default-configuration )
2018-07-24 01:44:51 +02:00
- [Custom Configuration ](#custom-configuration )
2018-07-08 00:15:12 +02:00
- [Recommended Configuration ](#recommended-configuration )
- [Available Rules ](#available-rules )
- [Available Formatters ](#available-formatters )
- [Friendly ](#friendly )
- [Stylish ](#stylish )
- [Default ](#default )
- [Extensibility ](#extensibility )
- [Custom Rule ](#custom-rule )
- [Example ](#example )
- [Custom Formatter ](#custom-formatter )
- [Speed Comparison ](#speed-comparison )
- [golint ](#golint )
- [revive ](#revive-1 )
- [Contributors ](#contributors )
- [License ](#license )
2018-06-08 19:28:17 +02:00
<!-- /TOC -->
2018-02-04 22:19:24 +02:00
## Usage
2018-05-27 00:17:28 +02:00
Since the default behavior of `revive` is compatible with `golint` , without providing any additional flags, the only difference you'd notice is faster execution.
2018-02-04 22:19:24 +02:00
2018-05-31 03:34:35 +02:00
### Text Editors
2018-06-08 19:28:17 +02:00
- Support for VSCode in [vscode-go ](https://github.com/Microsoft/vscode-go/pull/1699 ).
2018-07-31 21:20:58 +02:00
- Support for Atom via [linter-revive ](https://github.com/morphy2k/linter-revive ).
2018-06-09 01:04:26 +02:00
- Support for vim via [w0rp/ale ](https://github.com/w0rp/ale ):
2018-07-14 00:02:51 +02:00
2018-06-09 01:04:26 +02:00
```vim
call ale#linter#Define('go', {
\ 'name': 'revive',
\ 'output_stream': 'both',
\ 'executable': 'revive',
\ 'read_buffer': 0,
\ 'command': 'revive %t',
\ 'callback': 'ale#handlers#unix#HandleAsWarning',
\})
```
2018-07-14 00:02:51 +02:00
2018-05-27 01:19:34 +02:00
### Installation
```bash
go get -u github.com/mgechev/revive
```
2018-02-04 22:19:24 +02:00
### Command Line Flags
2018-05-27 00:17:28 +02:00
`revive` accepts three command line parameters:
2018-02-04 22:19:24 +02:00
2018-06-08 19:28:17 +02:00
- `-config [PATH]` - path to config file in TOML format.
- `-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:
2018-07-24 01:44:51 +02:00
2018-06-08 19:28:17 +02:00
- `default` - will output the failures the same way that `golint` does.
- `json` - outputs the failures in JSON format.
2018-07-14 00:01:27 +02:00
- `ndjson` - outputs the failures as stream in newline delimited JSON (NDJSON) format.
2018-06-08 19:28:17 +02:00
- `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.
2018-07-15 21:45:15 +02:00
- `checkstyle` - outputs the failures in XML format compatible with that of Java's [Checkstyle ](https://checkstyle.org/ ).
2018-07-24 01:44:51 +02:00
2018-05-27 00:17:28 +02:00
### Sample Invocations
```shell
revive -config revive.toml -exclude file1.go -exclude file2.go -formatter friendly github.com/mgechev/revive package/...
```
2018-06-08 19:28:17 +02:00
- 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`
2018-05-27 00:17:28 +02:00
2018-06-01 19:54:30 +02:00
### Comment Annotations
Using comments, you can disable the linter for the entire file or only range of lines:
```go
//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.
2018-08-14 22:22:52 +02:00
With `revive:disable-next-line` and `revive:disable-line` you can disable `revive` on a particular code line.
2018-06-01 19:54:30 +02:00
You can do the same on a rule level. In case you want to disable only a particular rule, you can use:
```go
//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.
2018-02-04 22:19:24 +02:00
### Configuration
2018-05-27 00:17:28 +02:00
`revive` can be configured with a TOML file. Here's a sample configuration with explanation for the individual properties:
```toml
2018-06-01 19:30:40 +02:00
# When set to false, ignores files with "GENERATED" header, similar to golint
2018-05-27 00:17:28 +02:00
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"
```
2018-02-04 22:19:24 +02:00
2018-02-04 23:42:05 +02:00
### Default Configuration
2018-02-19 08:19:37 +02:00
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` ).
2018-02-04 23:42:05 +02:00
```shell
revive -config defaults.toml github.com/mgechev/revive
```
2018-02-19 08:19:37 +02:00
This will use the configuration file `defaults.toml` , the `default` formatter, and will run linting over the `github.com/mgechev/revive` package.
2018-02-04 23:42:05 +02:00
2018-07-24 01:44:51 +02:00
### Custom Configuration
2018-02-04 23:42:05 +02:00
```shell
2018-05-27 00:17:28 +02:00
revive -config config.toml -formatter friendly github.com/mgechev/revive
2018-02-04 23:42:05 +02:00
```
2018-05-27 00:17:28 +02:00
This will use `config.toml` , the `friendly` formatter, and will run linting over the `github.com/mgechev/revive` package.
2018-02-04 23:42:05 +02:00
2018-07-24 01:44:51 +02:00
### Recommended Configuration
The following snippet contains the recommended `revive` configuration that you can use in your project:
```toml
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]
2018-09-14 04:21:28 +02:00
[rule.redefines-builtin-id]
2018-07-24 01:44:51 +02:00
```
2018-02-19 08:26:59 +02:00
## Available Rules
2018-06-13 21:35:38 +02:00
List of all available rules. The rules ported from `golint` are left unchanged and indicated in the `golint` column.
2018-05-27 01:16:10 +02:00
2018-06-01 06:14:00 +02:00
| 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 |
2018-09-04 16:18:28 +02:00
| `errorf` | n/a | Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()` | yes | yes |
2018-06-01 06:14:00 +02:00
| `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 |
2018-09-15 23:33:28 +02:00
| `var-naming` | whitelist & blacklist of initialisms | Naming rules. | yes | no |
2018-06-01 06:14:00 +02:00
| `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 |
2018-06-08 21:41:49 +02:00
| `empty-block` | n/a | Warns on empty code blocks | no | no |
2018-06-08 16:06:29 +02:00
| `superfluous-else` | n/a | Prevents redundant else statements (extends `indent-error-flow` ) | no | no |
2018-06-22 13:21:09 +02:00
| `confusing-naming` | n/a | Warns on methods with names that differ only by capitalization | no | no |
2018-07-08 00:15:12 +02:00
| `get-return` | n/a | Warns on getters that do not yield any result | no | no |
2018-07-15 03:39:49 +02:00
| `modifies-parameter` | n/a | Warns on assignments to function parameters | no | no |
2018-07-02 04:09:58 +02:00
| `confusing-results` | n/a | Suggests to name potentially confusing function results | no | no |
2018-06-26 22:21:03 +02:00
| `deep-exit` | n/a | Looks for program exits in funcs other than `main()` or `init()` | no | no |
2018-07-07 10:40:02 +02:00
| `unused-parameter` | n/a | Suggests to rename or remove unused function parameters | no | no |
2018-07-16 23:23:47 +02:00
| `unreachable-code` | n/a | Warns on unreachable code | no | no |
2018-07-24 01:44:51 +02:00
| `add-constant` | map | Suggests using constant for magic numbers and string literals | no | no |
2018-07-22 07:58:48 +02:00
| `flag-parameter` | n/a | Warns on boolean parameters that create a control coupling | no | no |
2018-07-28 07:38:39 +02:00
| `unnecessary-stmt` | n/a | Suggests removing or simplifying unnecessary statements | no | no |
2018-07-28 18:07:31 +02:00
| `struct-tag` | n/a | Checks common struct tags like `json` ,`xml`,`yaml` | no | no |
2018-08-14 00:18:28 +02:00
| `modifies-value-receiver` | n/a | Warns on assignments to value-passed method receivers | no | yes |
2018-08-23 20:45:10 +02:00
| `constant-logical-expr` | n/a | Warns on constant logical expressions | no | no |
2018-08-23 20:10:17 +02:00
| `bool-literal-in-expr` | n/a | Suggests removing Boolean literals from logic expressions | no | no |
2018-09-14 04:19:49 +02:00
| `redefines-builtin-id` | n/a | Warns on redefinitions of builtin identifiers | no | no |
2018-09-17 12:50:04 +02:00
| `function-result-limit` | int | Specifies the maximum number of results a function can return | no | no |
2018-09-17 22:06:42 +02:00
| `imports-blacklist` | []string | Disallows importing the specified packages | no | no |
2018-09-29 05:32:32 +02:00
| `range-val-in-closure` | n/a | Warns if range value is used in a closure dispatched as goroutine| no | no |
2018-10-03 08:12:19 +02:00
| `waitgroup-by-copy` | n/a | Warns on functions taking sync.WaitGroup as a by-copy parameter | no | no |
2018-10-01 21:24:17 +02:00
| `atomic` | n/a | Check for common mistaken usages of the `sync/atomic` package | no | no |
2018-02-19 08:26:59 +02:00
2018-09-15 23:33:28 +02:00
## 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 ](https://github.com/golang/lint/issues/89 ))
```toml
[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` .
2018-02-19 08:40:53 +02:00
## Available Formatters
This section lists all the available formatters and provides a screenshot for each one.
2018-05-26 23:12:02 +02:00
### Friendly
![Friendly formatter ](/assets/friendly-formatter.png )
2018-05-26 21:08:02 +02:00
### Stylish
2018-02-19 08:40:53 +02:00
2018-05-26 21:08:02 +02:00
![Stylish formatter ](/assets/stylish-formatter.png )
2018-02-19 08:40:53 +02:00
2018-05-26 23:12:02 +02:00
### Default
![Default formatter ](/assets/default-formatter.png )
2018-05-27 00:17:28 +02:00
## Extensibility
2018-02-05 01:40:39 +02:00
The tool can be extended with custom rules or formatters. This section contains additional information on how to implement such.
2018-05-27 00:17:28 +02:00
**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) ](https://golang.org/pkg/plugin/ ).
2018-02-05 01:40:39 +02:00
### Custom Rule
Each rule needs to implement the `lint.Rule` interface:
```go
type Rule interface {
Name() string
Apply(*File, Arguments) []Failure
}
```
2018-02-19 08:19:37 +02:00
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:
2018-02-05 01:40:39 +02:00
```toml
[rule.ban-struct-name]
2018-02-05 01:41:22 +02:00
arguments = ["Foo"]
2018-02-05 01:40:39 +02:00
```
With the snippet above we:
2018-06-08 19:28:17 +02:00
- 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.
2018-02-05 01:40:39 +02:00
A sample rule implementation can be found [here ](/rule/argument-limit.go ).
### Custom Formatter
Each formatter needs to implement the following interface:
```go
type Formatter interface {
Format(< -chan Failure , RulesConfig ) ( string , error )
Name() string
}
```
2018-02-19 08:19:37 +02:00
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.
2018-02-05 01:40:39 +02:00
For a sample formatter, take a look at [this file ](/formatter/json.go ).
2018-05-27 04:13:54 +02:00
## 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
```shell
time golint kubernetes/... > /dev/null
real 0m54.837s
user 0m57.844s
sys 0m9.146s
```
### revive
```shell
2018-06-01 05:00:04 +02:00
# no type checking
2018-06-01 06:14:00 +02:00
time revive -config untyped.toml kubernetes/... > /dev/null
2018-05-27 04:13:54 +02:00
2018-06-01 06:14:00 +02:00
real 0m8.471s
user 0m40.721s
sys 0m3.262s
2018-05-27 04:13:54 +02:00
```
2018-06-01 06:14:00 +02:00
Keep in mind that if you use rules which require type checking, the performance may drop to 2x faster than `golint` :
2018-06-01 04:53:26 +02:00
```shell
2018-06-01 05:00:04 +02:00
# type checking enabled
2018-06-01 04:53:26 +02:00
time revive kubernetes/... > /dev/null
real 0m26.211s
user 2m6.708s
sys 0m17.192s
```
2018-06-01 06:14:00 +02:00
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.
2018-06-01 04:53:26 +02:00
2018-06-08 19:24:28 +02:00
## Contributors
2018-09-20 19:47:03 +02:00
[<img alt="mgechev" src="https://avatars1.githubusercontent.com/u/455023?v=4&s=117" width="117"> ](https://github.com/mgechev ) |[< img alt = "chavacava" src = "https://avatars2.githubusercontent.com/u/25788468?v=4&s=117" width = "117" > ](https://github.com/chavacava) |[< img alt = "xuri" src = "https://avatars2.githubusercontent.com/u/2809468?v=4&s=117" width = "117" > ](https://github.com/xuri) |[< img alt = "morphy2k" src = "https://avatars2.githubusercontent.com/u/4280578?v=4&s=117" width = "117" > ](https://github.com/morphy2k) |[< img alt = "z0mbie42" src = "https://avatars0.githubusercontent.com/u/6172808?v=4&s=117" width = "117" > ](https://github.com/z0mbie42) |[< img alt = "tamird" src = "https://avatars0.githubusercontent.com/u/1535036?v=4&s=117" width = "117" > ](https://github.com/tamird) |
2018-09-09 02:48:14 +02:00
:---: |:---: |:---: |:---: |:---: |:---: |
2018-09-20 19:47:03 +02:00
[mgechev ](https://github.com/mgechev ) |[chavacava](https://github.com/chavacava) |[xuri](https://github.com/xuri) |[morphy2k](https://github.com/morphy2k) |[z0mbie42](https://github.com/z0mbie42) |[tamird](https://github.com/tamird) |
2018-07-21 01:56:37 +02:00
2018-09-20 19:47:03 +02:00
[<img alt="paul-at-start" src="https://avatars2.githubusercontent.com/u/5486775?v=4&s=117" width="117"> ](https://github.com/paul-at-start ) |[< img alt = "psapezhko" src = "https://avatars3.githubusercontent.com/u/10865586?v=4&s=117" width = "117" > ](https://github.com/psapezhko) |[< img alt = "Jarema" src = "https://avatars0.githubusercontent.com/u/7369771?v=4&s=117" width = "117" > ](https://github.com/Jarema) |[< img alt = "vkrol" src = "https://avatars3.githubusercontent.com/u/153412?v=4&s=117" width = "117" > ](https://github.com/vkrol) |[< img alt = "haya14busa" src = "https://avatars0.githubusercontent.com/u/3797062?v=4&s=117" width = "117" > ](https://github.com/haya14busa) |
:---: |:---: |:---: |:---: |:---: |
[paul-at-start ](https://github.com/paul-at-start ) |[psapezhko](https://github.com/psapezhko) |[Jarema](https://github.com/Jarema) |[vkrol](https://github.com/vkrol) |[haya14busa](https://github.com/haya14busa) |
2018-06-08 19:24:28 +02:00
2018-02-04 22:19:24 +02:00
## License
2017-08-28 05:57:46 +02:00
MIT
2018-09-20 19:47:03 +02:00