13 releases

0.1.0-pre.14 Apr 29, 2021
0.1.0-pre.13 Apr 14, 2021
0.1.0-pre.3 Mar 29, 2021
Download history 57/week @ 2021-03-24 36/week @ 2021-03-31 92/week @ 2021-04-07 120/week @ 2021-04-14 32/week @ 2021-04-21 34/week @ 2021-04-28

115 downloads per month
Used in 2 crates

MIT/Apache

37KB
776 lines

Dylint

A tool for running Rust lints from dynamic libraries

cargo install cargo-dylint --version '>=0.1.0-pre'

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

Quick start

The next five commands install Dylint, build one of its example libraries, and run the library's lint on the Dylint source code itself:

cargo install cargo-dylint dylint-link --version '>=0.1.0-pre' # Install cargo-dylint and dylint-link
git clone https://github.com/trailofbits/dylint                # Clone the Dylint repository
cd dylint/examples/allow_clippy                                # Go to one of the example lint libraries
cargo build                                                    # Build the library
cargo dylint allow_clippy -- --manifest-path ../../Cargo.toml  # Run the library's lint on the Dylint source code

You can start writing your own Dylint libraries by forking the dylint-template repository.

How libraries are found

When Dylint is started, the following locations are searched:

  • the colon-separated paths in DYLINT_LIBRARY_PATH (if set)
  • the current package's target/debug directory (if in a package)
  • the current package's target/release directory (if in a package)

Any file found in the above locations with a name of the form DLL_PREFIX LIBRARY_NAME '@' TOOLCHAIN DLL_SUFFIX (see Library requirements below) is considered a Dylint library.

In an invocation of the form cargo dylint <names>, each name in names is compared to the libraries found in the above manner. If name matches a discovered library's LIBRARY_NAME, then name resolves to that library. It is considered an error if a name resolves to multiple libraries.

If the above process does not resolve name to a library, then name is treated as a path.

If --lib name is used, then name is is treated only as a library name, and not as a path.

If --path name is used, then name is is treated only as a path, and not as a library name.

Library requirements

A Dylint library must satisfy four requirements. Note: before trying to satisfy these explicitly, see Utilities below.

  1. Have a filename of the form:

    DLL_PREFIX LIBRARY_NAME '@' TOOLCHAIN DLL_SUFFIX
    

    The following is a concrete example on Linux:

    libquestion_mark_in_expression@nightly-2021-04-08-x86_64-unknown-linux-gnu.so
    

    The filename components are as follows:

    • DLL_PREFIX and DLL_SUFFIX are OS-specific strings. For example, on Linux, they are lib and .so, respectively.
    • LIBARY_NAME is a name chosen by the library's author.
    • TOOLCHAIN is the Rust toolchain for which the library is compiled, e.g., nightly-2021-04-08-x86_64-unknown-linux-gnu.
  2. Export a dylint_version function:

    extern "C" fn dylint_version() -> *mut std::os::raw::c_char
    

    This function should return 0.1.0. This may change in future versions of Dylint.

  3. Export a register_lints function:

    fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore)
    

    This is a function called by the Rust compiler. It is documented here.

  4. Link against the rustc_driver dynamic library. This ensures the library uses Dylint's copies of the Rust compiler crates. This requirement can be satisfied by including the following declaration in your library's lib.rs file:

    extern crate rustc_driver;
    

Dylint provides utilities to help meet the above requirements. If your library uses the dylint-link tool and the dylint_library! macro, then all you should have to do is implement the register_lints function.

Utilities

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.

Limitations

To run a library's lints on a package, Dylint tries to build the package with the same toolchain used to build the library. So if a package requires a specific toolchain to build, Dylint may not be able to apply certain libraries to that package.

One way this problem can manifest itself is if you try to run one library's lints on the source code of another library. That is, if two libraries use different toolchains, they may not be applicable to each other.

Resources

Helpful resources for writing lints include the following:

Dependencies

~15MB
~340K SLoC