Crate marker_api

source ·
Expand description

Marker API

Crates.io License: MIT OR Apache-2.0

marker_api provides a representation of the AST and all connected types needed to create custom lint crates for Marker, an experimental linting interface for Rust.

Note

Marker is in the early stages of development, some things are still missing and the API still unstable.

A list of limitations and planned features can be found in Marker’s Readme.

Goals

  • Stability: Marker’s API design focuses on stability and expendability. The goal is to archive backwards compatibility, so that any lint, written after version 1.0.0, will compile and continue to work for years to come.
  • Usability: Marker’s API focuses on usability, where possible under the constraints of Marker’s stability guarantees. Types follow common design patterns and naming conventions, allowing you to focus on the lint logic directly.
  • Driver Independent: Every code analysis requires a driver that parses the code and provides further information. Marker’s API is designed to be driver-independent, allowing it to support future compilers and potentially IDEs. (Currently, rustc is the only available driver)

Usage

This section will cover how you can set up your own lint crate. If you only want to run custom lints, checkout Marker’s CLI interface cargo_marker. The rest of the section assumes that you have cargo_marker installed.

Template

The simplest way to get started, is to use Marker’s lint crate template, which already includes all dependencies, example code, and a working test setup.

Manual Setup

Cargo.toml

To get started, create a new Rust crate that compiles to a library (cargo init --lib). Afterwards, edit the Cargo.toml to compile the crate to a dynamic library and include marker_api as a dependency. You can simply add the following to your Cargo.toml file:

[lib]
crate-type = ["cdylib"]

[dependencies]
marker_api = "0.5.0"
marker_utils = "0.5.0"
src/lib.rs

The lint crate needs to provide an implementation of the LintPass trait and call the marker_api::export_lint_pass macro with the implementing type. Here is the minimal template:

use marker_api::prelude::*;
use marker_api::{LintPass, LintPassInfo, LintPassInfoBuilder};

// This is the struct that will implement the `LintPass` trait.
#[derive(Default)]
struct MyLintPass;

// This macro allow Marker to load the lint crate. Only one lint pass can be
// exported per lint crate.
marker_api::export_lint_pass!(MyLintPass);

// This macro declares a new lint, that can later be emitted
marker_api::declare_lint! {
    /// # What it does
    /// Here you can explain what your lint does. The description supports normal
    /// markdown.
    ///
    /// # Example
    /// ```rs
    /// // Bad example
    /// ```
    ///
    /// Use instead:
    /// ```rs
    /// // Good example
    /// ```
    MY_LINT,
    Warn,
}

// This is the actual `LintPass` implementation, which will be called by Marker.
impl LintPass for MyLintPass {
    fn info(&self) -> LintPassInfo {
        LintPassInfoBuilder::new(Box::new([MY_LINT])).build()
    }
}

Now you can implement different check_* function in the LintPass trait.

UI-Tests

To automatically test your lints, you might want to check out the marker_uitest crate.

And that’s it. Happy linting!

Contributing

Contributions are highly appreciated! If you encounter any issues or have suggestions for improvements, please check out Marker’s GitHub repository.

License

Copyright (c) 2022-2023 Rust-Marker

Rust-Marker is distributed under the terms of the MIT license or the Apache License (Version 2.0).

See LICENSE-APACHE, LICENSE-MIT.

Re-exports

Modules

  • A module containing the AST of Marker, which is the main syntactic representation of the written code.
  • This module provides types, which are used by the semantic and syntactic representations in Marker.
  • This module is responsible for the MarkerContext struct and related plumbing. Items in this module are generally unstable, with the exception of the exposed interface of MarkerContext.
  • This module is responsible for the construction of diagnostic messages. The DiagnosticBuilder is the public stable interface, to construct messages.
  • This prelude is a collection of traits and types which are commonly used when working with Marker. Simply add use marker_api::prelude::*; to your file, to import them all.
  • A module containing semantic representations of types, generics and other parts of the language.

Macros

  • This macro creates a new lint instance. The doc comment of the lint will be available in the crate documentation and any documentation generated by Marker. The content will be rendered with Markdown.
  • This macro marks the given struct as the main LintPass for the lint crate. For structs implementing Default it’s enough to only pass in the type. Otherwise, a second argument is required to initialize an instance.

Structs

  • This struct blocks the construction of enum variants, similar to the #[non_exhaustive] attribute.
  • This struct defines a lint.
  • This struct provides basic information required by the driver. It can also be used to provide additional information. The struct is constructed using the LintPassInfoBuilder.

Statics

Traits

  • A LintPass visits every node like a Visitor. The difference is that a LintPass provides some additional information about the implemented lints. The adapter will walk through the entire AST once and give each node to the registered LintPasses.