mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
2bcea4b04d
* Add LintableFilesVisitor * Move LintCommand logic into LintOrAnalyzeCommand to prepare for the upcoming analyze command * Add AnalyzeCommand (not fully implemented yet in SwiftLintFramework) * Add analyzerRules configuration member * Add AnalyzerRule protocol * Pass compiler arguments to validate/correct * Add requiresFileOnDisk member to RuleDescription This will be used by AnalyzerRules because they need a file on disk to pass in the compiler arguments to SourceKit. * Exclusively run AnalyzerRules when the Linter has compiler arguments * Enable testing AnalyzerRules in TestHelpers * Add ExplicitSelfRule * Update documentation * Fix `analyze --autocorrect` * Improve performance of CompilerArgumentsExtractor * Fix lint command actually running analyze * Move File operations in TestHelpers into a private extension * Add analyzer column to rules command and markdown documentation * Use a Set literal * Make AnalyzerRule inherit from OptInRule * Mention analyzer_rules in readme * Mention that analyzer rules are slow
473 lines
16 KiB
Markdown
473 lines
16 KiB
Markdown
# SwiftLint
|
|
|
|
A tool to enforce Swift style and conventions, loosely based on
|
|
[GitHub's Swift Style Guide](https://github.com/github/swift-style-guide).
|
|
|
|
SwiftLint hooks into [Clang](http://clang.llvm.org) and
|
|
[SourceKit](http://www.jpsim.com/uncovering-sourcekit) to use the
|
|
[AST](http://clang.llvm.org/docs/IntroductionToTheClangAST.html) representation
|
|
of your source files for more accurate results.
|
|
|
|

|
|
[](https://codecov.io/github/realm/SwiftLint?branch=master)
|
|
|
|

|
|
|
|
This project adheres to the [Contributor Covenant Code of Conduct](https://realm.io/conduct).
|
|
By participating, you are expected to uphold this code. Please report
|
|
unacceptable behavior to [info@realm.io](mailto:info@realm.io).
|
|
|
|
> Language Switch: [中文](https://github.com/realm/SwiftLint/blob/master/README_CN.md), [한국어](https://github.com/realm/SwiftLint/blob/master/README_KR.md).
|
|
|
|
## Installation
|
|
|
|
### Using [Homebrew](http://brew.sh/):
|
|
|
|
```
|
|
brew install swiftlint
|
|
```
|
|
|
|
### Using [CocoaPods](https://cocoapods.org):
|
|
|
|
Simply add the following line to your Podfile:
|
|
|
|
```ruby
|
|
pod 'SwiftLint'
|
|
```
|
|
|
|
This will download the SwiftLint binaries and dependencies in `Pods/` during your next
|
|
`pod install` execution and will allow you to invoke it via `${PODS_ROOT}/SwiftLint/swiftlint`
|
|
in your Script Build Phases.
|
|
|
|
This is the recommended way to install a specific version of SwiftLint since it supports
|
|
installing a pinned version rather than simply the latest (which is the case with Homebrew).
|
|
|
|
Note that this will add the SwiftLint binaries, its dependencies' binaries and the Swift binary
|
|
library distribution to the `Pods/` directory, so checking in this directory to SCM such as
|
|
git is discouraged.
|
|
|
|
### Using [Mint](https://github.com/yonaskolb/mint):
|
|
```
|
|
$ mint run realm/SwiftLint
|
|
```
|
|
|
|
### Using a pre-built package:
|
|
|
|
You can also install SwiftLint by downloading `SwiftLint.pkg` from the
|
|
[latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and
|
|
running it.
|
|
|
|
### Compiling from source:
|
|
|
|
You can also build from source by cloning this project and running
|
|
`git submodule update --init --recursive; make install` (Xcode 9.0 or later).
|
|
|
|
## Usage
|
|
|
|
### Presentation
|
|
|
|
To get a high-level overview of recommended ways to integrate SwiftLint into your project,
|
|
we encourage you to watch this presentation or read the transcript:
|
|
|
|
[](https://academy.realm.io/posts/slug-jp-simard-swiftlint/)
|
|
|
|
### Xcode
|
|
|
|
Integrate SwiftLint into an Xcode scheme to get warnings and errors displayed
|
|
in the IDE. Just add a new "Run Script Phase" with:
|
|
|
|
```bash
|
|
if which swiftlint >/dev/null; then
|
|
swiftlint
|
|
else
|
|
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
|
|
fi
|
|
```
|
|
|
|

|
|
|
|
Alternatively, if you've installed SwiftLint via CocoaPods the script should look like this:
|
|
|
|
```bash
|
|
"${PODS_ROOT}/SwiftLint/swiftlint"
|
|
```
|
|
|
|
#### Format on Save Xcode Plugin
|
|
|
|
To run `swiftlint autocorrect` on save in Xcode, install the
|
|
[SwiftLintXcode](https://github.com/ypresto/SwiftLintXcode) plugin from Alcatraz.
|
|
|
|
⚠️This plugin will not work with Xcode 8 or later without disabling SIP.
|
|
This is not recommended.
|
|
|
|
### AppCode
|
|
|
|
To integrate SwiftLint with AppCode, install
|
|
[this plugin](https://plugins.jetbrains.com/plugin/9175) and configure
|
|
SwiftLint's installed path in the plugin's preferences.
|
|
The `autocorrect` action is available via `⌥⏎`.
|
|
|
|
### Atom
|
|
|
|
To integrate SwiftLint with [Atom](https://atom.io/), install the
|
|
[`linter-swiftlint`](https://atom.io/packages/linter-swiftlint) package from
|
|
APM.
|
|
|
|
### fastlane
|
|
|
|
You can use the [official swiftlint fastlane action](https://docs.fastlane.tools/actions/swiftlint) to run SwiftLint as part of your fastlane process.
|
|
|
|
```ruby
|
|
swiftlint(
|
|
mode: :lint, # SwiftLint mode: :lint (default) or :autocorrect
|
|
executable: "Pods/SwiftLint/swiftlint", # The SwiftLint binary path (optional). Important if you've installed it via CocoaPods
|
|
path: "/path/to/lint", # Specify path to lint (optional)
|
|
output_file: "swiftlint.result.json", # The path of the output file (optional)
|
|
reporter: "json", # The custom reporter to use (optional)
|
|
config_file: ".swiftlint-ci.yml", # The path of the configuration file (optional)
|
|
files: [ # List of files to process (optional)
|
|
"AppDelegate.swift",
|
|
"path/to/project/Model.swift"
|
|
],
|
|
ignore_exit_status: true, # Allow fastlane to continue even if SwiftLint returns a non-zero exit status (Default: false)
|
|
quiet: true, # Don't print status logs like 'Linting ' & 'Done linting' (Default: false)
|
|
strict: true # Fail on warnings? (Default: false)
|
|
)
|
|
```
|
|
|
|
|
|
### Command Line
|
|
|
|
```
|
|
$ swiftlint help
|
|
Available commands:
|
|
|
|
analyze [Experimental] Run analysis rules
|
|
autocorrect Automatically correct warnings and errors
|
|
generate-docs Generates markdown documentation for all rules
|
|
help Display general or command-specific help
|
|
lint Print lint warnings and errors (default command)
|
|
rules Display the list of rules and their identifiers
|
|
version Display the current version of SwiftLint
|
|
```
|
|
|
|
Run `swiftlint` in the directory containing the Swift files to lint. Directories
|
|
will be searched recursively.
|
|
|
|
To specify a list of files when using `lint`, `autocorrect` or `analyze`
|
|
(like the list of files modified by Xcode specified by the
|
|
[`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) Xcode
|
|
plugin, or modified files in the working tree based on `git ls-files -m`), you
|
|
can do so by passing the option `--use-script-input-files` and setting the
|
|
following instance variables: `SCRIPT_INPUT_FILE_COUNT` and
|
|
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT}`.
|
|
|
|
These are same environment variables set for input files to
|
|
[custom Xcode script phases](http://indiestack.com/2014/12/speeding-up-custom-script-phases/).
|
|
|
|
### Working With Multiple Swift Versions
|
|
|
|
SwiftLint hooks into SourceKit so it continues working even as Swift evolves!
|
|
|
|
This also keeps SwiftLint lean, as it doesn't need to ship with a full Swift
|
|
compiler, it just communicates with the official one you already have installed
|
|
on your machine.
|
|
|
|
You should always run SwiftLint with the same toolchain you use to compile your
|
|
code.
|
|
|
|
You may want to override SwiftLint's default Swift toolchain if you have
|
|
multiple toolchains or Xcodes installed.
|
|
|
|
Here's the order in which SwiftLint determines which Swift toolchain to use:
|
|
|
|
* `$XCODE_DEFAULT_TOOLCHAIN_OVERRIDE`
|
|
* `$TOOLCHAIN_DIR` or `$TOOLCHAINS`
|
|
* `xcrun -find swift`
|
|
* `/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
|
|
* `/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
|
|
* `~/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
|
|
* `~/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
|
|
|
|
`sourcekitd.framework` is expected to be found in the `usr/lib/` subdirectory of
|
|
the value passed in the paths above.
|
|
|
|
You may also set the `TOOLCHAINS` environment variable to the reverse-DNS
|
|
notation that identifies a Swift toolchain version:
|
|
|
|
```shell
|
|
$ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
|
|
```
|
|
|
|
On Linux, SourceKit is expected to be located in
|
|
`/usr/lib/libsourcekitdInProc.so` or specified by the `LINUX_SOURCEKIT_LIB_PATH`
|
|
environment variable.
|
|
|
|
### Swift Version Support
|
|
|
|
Here's a reference of which SwiftLint version to use for a given Swift version.
|
|
|
|
| Swift version | Last supported SwiftLint release |
|
|
| ------------- | -------------------------------- |
|
|
| Swift 1.x | SwiftLint 0.1.2 |
|
|
| Swift 2.x | SwiftLint 0.18.1 |
|
|
| Swift 3.x | Latest |
|
|
| Swift 4.x | Latest |
|
|
|
|
## Rules
|
|
|
|
Over 75 rules are included in SwiftLint and the Swift community (that's you!)
|
|
continues to contribute more over time.
|
|
[Pull requests](CONTRIBUTING.md) are encouraged.
|
|
|
|
You can find an updated list of rules and more information about them
|
|
in [Rules.md](Rules.md).
|
|
|
|
You can also check [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules)
|
|
directory to see their implementation.
|
|
|
|
### Opt-In Rules
|
|
|
|
`opt_in_rules` are disabled by default (i.e., you have to explicitly enable them
|
|
in your configuration file).
|
|
|
|
Guidelines on when to mark a rule as opt-in:
|
|
|
|
* A rule that can have many false positives (e.g. `empty_count`)
|
|
* A rule that is too slow
|
|
* A rule that is not general consensus or is only useful in some cases
|
|
(e.g. `force_unwrapping`)
|
|
|
|
### Disable rules in code
|
|
|
|
Rules can be disabled with a comment inside a source file with the following
|
|
format:
|
|
|
|
`// swiftlint:disable <rule1> [<rule2> <rule3>...]`
|
|
|
|
The rules will be disabled until the end of the file or until the linter sees a
|
|
matching enable comment:
|
|
|
|
`// swiftlint:enable <rule1> [<rule2> <rule3>...]`
|
|
|
|
For example:
|
|
|
|
```swift
|
|
// swiftlint:disable colon
|
|
let noWarning :String = "" // No warning about colons immediately after variable names!
|
|
// swiftlint:enable colon
|
|
let hasWarning :String = "" // Warning generated about colons immediately after variable names
|
|
```
|
|
|
|
Including the `all` keyword will disable all rules until the linter sees a matching enable comment:
|
|
|
|
`// swiftlint:disable all`
|
|
`// swiftlint:enable all`
|
|
|
|
For example:
|
|
|
|
```swift
|
|
// swiftlint:disable all
|
|
let noWarning :String = "" // No warning about colons immediately after variable names!
|
|
let i = "" // Also no warning about short identifier names
|
|
// swiftlint:enable all
|
|
let hasWarning :String = "" // Warning generated about colons immediately after variable names
|
|
let y = "" // Warning generated about short identifier names
|
|
```
|
|
|
|
It's also possible to modify a `disable` or `enable` command by appending
|
|
`:previous`, `:this` or `:next` for only applying the command to the previous,
|
|
this (current) or next line respectively.
|
|
|
|
For example:
|
|
|
|
```swift
|
|
// swiftlint:disable:next force_cast
|
|
let noWarning = NSNumber() as! Int
|
|
let hasWarning = NSNumber() as! Int
|
|
let noWarning2 = NSNumber() as! Int // swiftlint:disable:this force_cast
|
|
let noWarning3 = NSNumber() as! Int
|
|
// swiftlint:disable:previous force_cast
|
|
```
|
|
|
|
Run `swiftlint rules` to print a list of all available rules and their
|
|
identifiers.
|
|
|
|
### Configuration
|
|
|
|
Configure SwiftLint by adding a `.swiftlint.yml` file from the directory you'll
|
|
run SwiftLint from. The following parameters can be configured:
|
|
|
|
Rule inclusion:
|
|
|
|
* `disabled_rules`: Disable rules from the default enabled set.
|
|
* `opt_in_rules`: Enable rules not from the default set.
|
|
* `whitelist_rules`: Acts as a whitelist, only the rules specified in this list
|
|
will be enabled. Can not be specified alongside `disabled_rules` or
|
|
`opt_in_rules`.
|
|
* `analyzer_rules`: This is an entirely separate list of rules that are only
|
|
run by the `analyze` command. All analyzer rules are opt-in, so this is the
|
|
only configurable rule list (there is no disabled/whitelist equivalent).
|
|
|
|
```yaml
|
|
disabled_rules: # rule identifiers to exclude from running
|
|
- colon
|
|
- comma
|
|
- control_statement
|
|
opt_in_rules: # some rules are only opt-in
|
|
- empty_count
|
|
# Find all the available rules by running:
|
|
# swiftlint rules
|
|
included: # paths to include during linting. `--path` is ignored if present.
|
|
- Source
|
|
excluded: # paths to ignore during linting. Takes precedence over `included`.
|
|
- Carthage
|
|
- Pods
|
|
- Source/ExcludedFolder
|
|
- Source/ExcludedFile.swift
|
|
- Source/*/ExcludedFile.swift # Exclude files with a wildcard
|
|
analyzer_rules: # Rules run by `swiftlint analyze` (experimental)
|
|
- explicit_self
|
|
|
|
# configurable rules can be customized from this configuration file
|
|
# binary rules can set their severity level
|
|
force_cast: warning # implicitly
|
|
force_try:
|
|
severity: warning # explicitly
|
|
# rules that have both warning and error levels, can set just the warning level
|
|
# implicitly
|
|
line_length: 110
|
|
# they can set both implicitly with an array
|
|
type_body_length:
|
|
- 300 # warning
|
|
- 400 # error
|
|
# or they can set both explicitly
|
|
file_length:
|
|
warning: 500
|
|
error: 1200
|
|
# naming rules can set warnings/errors for min_length and max_length
|
|
# additionally they can set excluded names
|
|
type_name:
|
|
min_length: 4 # only warning
|
|
max_length: # warning and error
|
|
warning: 40
|
|
error: 50
|
|
excluded: iPhone # excluded via string
|
|
identifier_name:
|
|
min_length: # only min_length
|
|
error: 4 # only error
|
|
excluded: # excluded via string array
|
|
- id
|
|
- URL
|
|
- GlobalAPIKey
|
|
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube)
|
|
```
|
|
|
|
You can also use environment variables in your configuration file,
|
|
by using `${SOME_VARIABLE}` in a string.
|
|
|
|
#### Defining Custom Rules
|
|
|
|
You can define custom regex-based rules in your configuration file using the
|
|
following syntax:
|
|
|
|
```yaml
|
|
custom_rules:
|
|
pirates_beat_ninjas: # rule identifier
|
|
included: ".*\\.swift" # regex that defines paths to include during linting. optional.
|
|
excluded: ".*Test\\.swift" # regex that defines paths to exclude during linting. optional
|
|
name: "Pirates Beat Ninjas" # rule name. optional.
|
|
regex: "([n,N]inja)" # matching pattern
|
|
match_kinds: # SyntaxKinds to match. optional.
|
|
- comment
|
|
- identifier
|
|
message: "Pirates are better than ninjas." # violation message. optional.
|
|
severity: error # violation severity. optional.
|
|
no_hiding_in_strings:
|
|
regex: "([n,N]inja)"
|
|
match_kinds: string
|
|
```
|
|
|
|
This is what the output would look like:
|
|
|
|

|
|
|
|
You can filter the matches by providing one or more `match_kinds`, which will
|
|
reject matches that include syntax kinds that are not present in this list. Here
|
|
are all the possible syntax kinds:
|
|
|
|
* argument
|
|
* attribute.builtin
|
|
* attribute.id
|
|
* buildconfig.id
|
|
* buildconfig.keyword
|
|
* comment
|
|
* comment.mark
|
|
* comment.url
|
|
* doccomment
|
|
* doccomment.field
|
|
* identifier
|
|
* keyword
|
|
* number
|
|
* objectliteral
|
|
* parameter
|
|
* placeholder
|
|
* string
|
|
* string_interpolation_anchor
|
|
* typeidentifier
|
|
|
|
If using custom rules alongside a whitelist, make sure to add `custom_rules` as an item under `whitelist_rules`.
|
|
|
|
#### Nested Configurations
|
|
|
|
SwiftLint supports nesting configuration files for more granular control over
|
|
the linting process.
|
|
|
|
* Include additional `.swiftlint.yml` files where necessary in your directory
|
|
structure.
|
|
* Each file will be linted using the configuration file that is in its
|
|
directory or at the deepest level of its parent directories. Otherwise the
|
|
root configuration will be used.
|
|
* `excluded` and `included` are ignored for nested
|
|
configurations.
|
|
|
|
### Auto-correct
|
|
|
|
SwiftLint can automatically correct certain violations. Files on disk are
|
|
overwritten with a corrected version.
|
|
|
|
Please make sure to have backups of these files before running
|
|
`swiftlint autocorrect`, otherwise important data may be lost.
|
|
|
|
Standard linting is disabled while correcting because of the high likelihood of
|
|
violations (or their offsets) being incorrect after modifying a file while
|
|
applying corrections.
|
|
|
|
### Analyze (experimental)
|
|
|
|
The _experimental_ `swiftlint analyze` command can lint Swift files using the
|
|
full type-checked AST. The compiler log path containing the clean `swiftc` build
|
|
command invocation (incremental builds will fail) must be passed to `analyze`
|
|
via the `--compiler-log-path` flag.
|
|
e.g. `--compiler-log-path /path/to/xcodebuild.log`
|
|
|
|
This command and related code in SwiftLint is subject to substantial changes at
|
|
any time while this feature is marked as experimental. Analyzer rules also tend
|
|
to be considerably slower than lint rules.
|
|
|
|
## License
|
|
|
|
[MIT licensed.](LICENSE)
|
|
|
|
## About
|
|
|
|
<img src="assets/realm.png" width="184" />
|
|
|
|
SwiftLint is maintained and funded by Realm Inc. The names and logos for
|
|
Realm are trademarks of Realm Inc.
|
|
|
|
We :heart: open source software!
|
|
See [our other open source projects](https://github.com/realm),
|
|
read [our blog](https://realm.io/news), or say hi on twitter
|
|
([@realm](https://twitter.com/realm)).
|