A tool for running Rust lints from dynamic libraries
sh
cargo install cargo-dylint dylint-link
Dylint is a Rust linting tool, similar to Clippy. But whereas Clippy runs a predetermined, static set of lints, Dylint runs lints from user-specified, dynamic libraries. Thus, Dylint allows developers to maintain their own personal lint collections.
Contents
Documentation is also available on [how Dylint works].
The next three steps install Dylint and run all of this repository's [general-purpose, example lints] on a workspace:
Install cargo-dylint
and dylint-link
:
sh
cargo install cargo-dylint dylint-link
Add the following to the workspace's Cargo.toml
file:
toml
[workspace.metadata.dylint]
libraries = [
{ git = "https://github.com/trailofbits/dylint", pattern = "examples/general/*" },
]
Run cargo-dylint
:
sh
cargo dylint --all --workspace
In the above example, the libraries are found via [workspace metadata], which is the recommended way. For additional ways of finding libraries, see [How Dylint works].
You can start writing your own Dylint library by running cargo dylint new new_lint_name
. Doing so will produce a loadable library right out of the box. You can verify this as follows:
sh
cargo dylint new new_lint_name
cd new_lint_name
cargo build
DYLINT_LIBRARY_PATH=$PWD/target/debug cargo dylint list --lib new_lint_name
All you have to do is implement the [LateLintPass
] trait and accommodate the symbols asking to be filled in.
Helpful [resources] for writing lints appear below.
A workspace can name the libraries it should be linted with in its Cargo.toml
file. Specifically, a workspace's manifest can contain a TOML list under workspace.metadata.dylint.libraries
. Each list entry must have the form of a Cargo git
or path
dependency, with the following differences:
package =
.path
entries can contain [glob] patterns, e.g., *
.pattern
field whose value is a [glob] pattern. The pattern
field indicates the subdirectories that contain Dylint libraries.Dylint downloads and builds each entry, similar to how Cargo downloads and builds a dependency. The resulting target/release
directories are searched for files with names of the form that Dylint recognizes (see [Library requirements] under [How Dylint works]).
As an example, if you include the following in your workspace's Cargo.toml
file and run cargo dylint --all --workspace
, Dylint will run on your workspace all of this repository's [example general-purpose lints], as well as the example restriction lint [try_io_result
].
toml
[workspace.metadata.dylint]
libraries = [
{ git = "https://github.com/trailofbits/dylint", pattern = "examples/general/*" },
{ git = "https://github.com/trailofbits/dylint", pattern = "examples/restriction/try_io_result" },
]
Libraries can be configured by including a dylint.toml
file in a linted workspace's root directory. The file should encode a [toml table] whose keys are library names. A library determines how its value in the table (if any) is interpreted.
As an example, a dylint.toml
file with the following contents sets the [non_local_effect_before_error_return
] library's work_limit
configuration to 1_000_000
:
toml
[non_local_effect_before_error_return]
work_limit = 1_000_000
For instructions on creating a configurable library, see the [dylint_linting
] documentation.
For each library that Dylint uses to check a crate, Dylint passes the following to the Rust compiler:
sh
--cfg=dylint_lib="LIBRARY_NAME"
You can use this feature to allow a lint when Dylint is used, but also avoid an "unknown lint" warning when Dylint is not used. Specifically, you can do the following:
```rust
```
Note that LIBRARY_NAME
and LINT_NAME
may be the same. For an example involving [non_thread_safe_call_in_test
], see [dylint/src/lib.rs] in this repository.
Also note that the just described approach does not work for pre-expansion lints. The only known workaround for pre-expansion lints is allow the compiler's built-in [unknown_lints
] lint. Specifically, you can do the following:
```rust
```
For an example involving [env_cargo_path
], see [internal/src/examples.rs] in this repository.
Dylint results can be viewed in VS Code using [rust-analyzer]. To do so, add the following to your VS Code settings.json
file:
json
"rust-analyzer.checkOnSave.overrideCommand": [
"cargo",
"dylint",
"--all",
"--workspace",
"--",
"--all-targets",
"--message-format=json"
]
If you want to use rust-analyzer inside a lint library, you need to add the following to your VS Code settings.json
file:
json
"rust-analyzer.rustc.source": "discover",
And add the following to the library's Cargo.toml
file:
toml
[package.metadata.rust-analyzer]
rustc_private = true
The following utilities can be helpful for writing Dylint libraries:
dylint-link
] is a wrapper around Rust's default linker (cc
) that creates a copy of your library with a filename that Dylint recognizes.dylint_library!
] is a macro that automatically defines the dylint_version
function and adds the extern crate rustc_driver
declaration.ui_test
] is a function that can be used to test Dylint libraries. It provides convenient access to the [compiletest_rs
] package.clippy_utils
] is a collection of utilities to make writing lints easier. It is generously made public by the Rust Clippy Developers. Note that, like rustc
, clippy_utils
provides no stability guarantees for its APIs.Helpful resources for writing lints include the following:
rustc_hir
]rustc_middle
]rustc_lint::LateContext
]
typeck_results
]tcx
]hir
]