Introduction
This is the combined documentation for the prototype Bevy CLI and Bevy Linter projects, tools designed to improve the experience developing apps using the Bevy game engine. To get started, take a look about the about pages for one of the tools:
This is an unofficial community project, hacked upon by the Bevy CLI working group until it is eventually upstreamed into the main Bevy Engine organization. Pardon our rough edges, and please consider submitting an issue or reaching out in the Bevy Discord if you run into trouble!
Bevy CLI (Alpha)
The CLI is a prototype tool intended to streamline common tasks when working on projects. Please see the initial scope document and original issue for history and motivation. The CLI's current features include:
This is an unofficial community project, hacked upon by the Bevy CLI working group until it is eventually upstreamed into the main Bevy Engine organization. Pardon our rough edges, and please consider submitting an issue or reaching out in the Bevy Discord if you run into trouble!
Installation
As the CLI is currently an unofficial tool, it is not yet published to https://crates.io. It is available on Github, however.
Precompiled Binary
The CLI is precompiled for Linux, Windows, and MacOS. You may install the latest precompiled binary using cargo-binstall
:
cargo binstall --git https://github.com/TheBevyFlock/bevy_cli --locked bevy_cli
You can manually download the precompiled binaries from the release page.
Build from Source
You may compile the CLI from scratch using cargo install
. To install the latest release, make sure to specify the version you wish in the tag (ex. --tag cli-v0.1.0-alpha.1
).
cargo install --git https://github.com/TheBevyFlock/bevy_cli --tag cli-vX.Y.Z --locked bevy_cli
Bleeding Edge
Here be dragons! 🐉
You may run into bugs when using the unstable version of the CLI. You've been warned, and have fun! :)
If you want to try out the newest unstable features, you may install the CLI from the main
branch:
cargo install --git https://github.com/TheBevyFlock/bevy_cli --branch main --locked bevy_cli
Quick Start
With the following steps, you can create a new 2D app with Bevy and run it in your browser:
-
Create a new Bevy app using the 2D template:
bevy new -t=2d my_bevy_app
-
Navigate into the folder:
cd my_bevy_app
-
Check the code quality with the linter:
bevy lint
-
Run the app in the browser:
bevy run web --open
Scaffolding
The bevy new
command lets you easily scaffold a new Bevy project using a custom template or a minimal template provided by Bevy. Templates are just GitHub repositories and can be specified with the -t
flag.
Usage
If the template is omitted, the default minimal template will be chosen.
bevy new my-project
Other built-in templates from TheBevyFlock will be usable via its shortcut form i.e. -t 2d
will use the template bevy_new_2d.
bevy new my-project -t 2d
To use a specific template, provide the full GitHub URL:
bevy new my-project -t https://github.com/TheBevyFlock/bevy_new_2d.git
Web Apps
The CLI makes it easy to build and run web apps made with Bevy, using bevy build web
and bevy run web
.
It takes care of compiling the app to Wasm, creating JavaScript bindings and serving it on a local web server to test it out.
If you are missing any required tools, the CLI will ask you to install them for you automatically.
Note
The arguments you know from
cargo
(like--release
) must be placed before theweb
subcommand, while the web-specific options (like--open
) must be placed afterwards, e.g.bevy run --release web --open
Running in the browser
Use the bevy run web
command to run your app in the browser.
The app will be automatically served on a local web server, use the --open
flag to automatically open it in the browser.
The server will provide a default index.html
serving as entrypoint for your app.
It features a loading screen and some other utilities.
If you want to customize it, simply create a web/index.html
file to override the default behavior.
Other files in the web
folder will also be included in your application.
You can view the default index.html
here.
Creating web bundles
To deploy your app on a web server, it's often necessary to bundle the binary, assets and web files into a single folder.
Using bevy build web --bundle
, the CLI can create this bundle for you automatically.
It will be available in the target/bevy_web
folder, see the command's output for the full file path.
Compilation profiles
Web apps have different needs than native builds when it comes to compilation. For example, binary size is a lot more important for web apps, as it has a big influence on the loading times.
The Bevy CLI provides custom web
and web-release
compilation profiles, which are optimized for web apps.
They are used by default for the web sub-commands (depending on the --release
flag).
The profiles can be customized as usual in Cargo.toml
:
[profile.web-release]
inherits = "release"
opt-level = "z"
Alternatively, you can change the profile entirely, e.g. bevy run --profile=foo web
.
Feature configuration
Often, you want to enable certain features only in development mode or only for native and not web builds.
In your Cargo.toml
you can enable features or disable default features depending on platform (native
/web
) and profile (dev
/release
):
[package.metadata.bevy_cli.native.dev]
features = [
# Enable asset hot reloading for native dev builds.
"bevy/file_watcher",
# Enable embedded asset hot reloading for native dev builds.
"bevy/embedded_watcher",
]
[package.metadata.bevy_cli.web]
# Disable default features for web builds
default-features = false
Usage in CI
The CLI may include interactive prompts if parts of the required tooling is not installed on the system. These prompts will break your pipeline if they are triggered in CI.
To avoid this problem, use the --yes
flag to automatically confirm the prompts:
bevy build --yes web
Default index.html
This is the default index.html
that bevy build web
and bevy run web
uses to load your application. You may customize index.html
by creating a web/index.html
to override the default. The default is provided below, so you can copy it instead of writing your own from scratch:
Warning
The default index.html
has the following line:
import init from "./build/bevy_app.js";
You will need to replace bevy_app
with the name of your compiled binary. This is usually your crate's name, but it can be customized in Cargo.toml
with the [[bin]]
table, so be careful!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<style>
/* Styles for the loading screen */
:root {
--web-bg-color: #2b2c2f;
--web-color: white;
}
* {
margin: 0;
padding: 0;
border: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.center {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
body {
background-color: var(--web-bg-color);
color: var(--web-color);
}
.spinner {
width: 128px;
height: 128px;
border: 64px solid transparent;
border-bottom-color: #ececec;
border-right-color: #b2b2b2;
border-top-color: #787878;
border-radius: 50%;
box-sizing: border-box;
animation: spin 1.2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body class="center">
<noscript>JavaScript support is required to run this app</noscript>
<div id="loading-screen" class="center">
<span class="spinner"></span>
</div>
<script type="module">
// Automatically restart the audio context after user interaction
// Needs to be executed _before_ the game is loaded
// Taken from https://developer.chrome.com/blog/web-audio-autoplay/#moving-forward
(function () {
// An array of all contexts to resume on the page
const audioContextList = [];
// An array of various user interaction events we should listen for
const userInputEventNames = [
"click",
"contextmenu",
"auxclick",
"dblclick",
"mousedown",
"mouseup",
"pointerup",
"touchend",
"keydown",
"keyup",
];
// A proxy object to intercept AudioContexts and
// add them to the array for tracking and resuming later
self.AudioContext = new Proxy(self.AudioContext, {
construct(target, args) {
const result = new target(...args);
audioContextList.push(result);
return result;
},
});
// To resume all AudioContexts being tracked
function resumeAllContexts(event) {
let count = 0;
audioContextList.forEach((context) => {
if (context.state !== "running") {
context.resume();
} else {
count++;
}
});
// If all the AudioContexts have now resumed then we
// unbind all the event listeners from the page to prevent
// unnecessary resume attempts
if (count == audioContextList.length) {
userInputEventNames.forEach((eventName) => {
document.removeEventListener(eventName, resumeAllContexts);
});
}
}
// We bind the resume function for each user interaction
// event on the page
userInputEventNames.forEach((eventName) => {
document.addEventListener(eventName, resumeAllContexts);
});
})();
</script>
<script type="module">
// Starting the game
// When this file is used as the default `index.html`, the CLI will automatically replace
// `bevy_app.js` with the name of the generated JS entrypoint. If you copy this file and
// customize it, you will need to manually change the name. For more information, please see
// <https://thebevyflock.github.io/bevy_cli/cli/web/default-index-html.html>!
import init from "./build/bevy_app.js";
init().catch((error) => {
if (
!error.message.startsWith(
"Using exceptions for control flow, don't mind me. This isn't actually an error!"
)
) {
throw error;
}
});
</script>
<script type="module">
// Hide loading screen when the game starts.
const loading_screen = document.getElementById("loading-screen");
const observer = new MutationObserver((records) => {
for (const record of records) {
for (const addedNode of record.addedNodes) {
if (addedNode instanceof HTMLCanvasElement) {
if (addedNode.innerText.trim().length === 0) {
// Add compatibility note
addedNode.innerText =
"Canvas support is required to run this app";
}
// A new canvas has been created, which means that the game has been loaded
// Hide the loading screen!
loading_screen.style.display = "none";
observer.disconnect();
return;
}
}
}
});
observer.observe(document.body, {
subtree: false,
childList: true,
attributes: false,
characterData: false,
});
</script>
</body>
</html>
Linter
The CLI has 1st-party support for bevy_lint
, the static analysis tool that checks over your code.
bevy lint
If you do not have the linter installed already, the CLI can install it for you when you first run the command. Calling the lint
subcommand is equivalent to calling bevy_lint
, and supports the same arguments as cargo check
:
bevy lint --workspace --all-features
You can view a full list of options with:
bevy lint -- --help
Configuration
The CLI can be configured on a per project basis in the Cargo.toml
under the metadata
section.
[package.metadata.bevy_cli]
The CLI supports two targets:
- native:
[package.metadata.bevy_cli.native]
- web:
[package.metadata.bevy_cli.web]
For both these targets a release and dev profile
exists that will automatically be chosen by the CLI:
Profile Name | Configuration Section |
---|---|
release | [package.metadata.bevy_cli.native.release] |
dev | [package.metadata.bevy_cli.native.dev] |
web-release | [package.metadata.bevy_cli.web.release] |
web | [package.metadata.bevy_cli.web.dev] |
Note
The Web profiles inherits from their native counterpart
Configuration Merging
Configuration is merged in the following order (from general to specific):
- Base config:
[package.metadata.bevy_cli]
- Profile config
[package.metadata.bevy_cli.{dev|release)]
- Target config:
[package.metadata.bevy_cli.{native|web}]
- Target + Profile config:
[package.metadata.bevy_cli.{native|web}.{dev|release}]
Example
The following Cargo.toml
[package.metadata.bevy_cli]
default-features = true
[package.metadata.bevy_cli.web]
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
[package.metadata.bevy_cli.web.release]
wasm-opt = true
[package.metadata.bevy_cli.release]
default-features = false
When building for web in release mode, the final merged configuration will be:
# merged from `[package.metadata.bevy_cli.web]`
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
# merged from `[package.metadata.bevy_cli.web.release]`
wasm-opt = true
# merged from `[package.metadata.bevy_cli.release]`
default-features = false
When building for native dev, the final merged configuration will be:
# merged from [package.metadata.bevy_cli] (default-features are enabled by default if not explicitly turned off)
default-features = true
Configuration Reference
The following fields exist and can be configured:
features
- Type: array of strings
- Default: none
- Note: Which features to use.
default-features
- Type: boolean
- Default: true
- Note: Whether or not to use the default-features
rustflags
- Type: string or array of strings
- Default: none
- Note: Extra command-line flags to pass to rustc. The value may be an array of strings or a space-separated string.
wasm-opt
- Type: boolean
- Default: true for release web builds
- Note: Whether or not to use
wasm-opt
to optimize the web binary.
Troubleshooting
If you encounter issues or don't understand what the CLI is doing, try the --verbose
flag. Every command that the CLI executes will be logged, making it easy to understand what's going on!
Changelog
All notable user-facing changes to the Bevy CLI will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
All Changes: cli-v0.1.0-alpha.1...main
v0.1.0-alpha.1 - 2025-05-23
All Changes: cli-v0.1.0-alpha.1
Added
bevy new
: create new projects from a template usingcargo-generate
(#2)bevy_new_minimal
is the default template if none is specified (#80)- There are shortcuts for templates from TheBevyFlock. For example,
-t 2d
usesbevy_new_2d
(#82)
bevy lint
: invoke the linter ifbevy_lint
is installed (#4)bevy build
andbevy run
: build and run your program with Bevy-specific configuration (#76, #103, #102, #120)bevy completions
: generate terminal auto-complete scripts for a variety of shells (#265)- The CLI can be configured with
[package.metadata.bevy_cli]
(#331, #355, #351)
Migration Guide
Occasionally changes are made to the Bevy CLI that may break existing projects, or majorly change how it is intended to be used. This document provides a guide recommending how to upgrade your existing project to a newer version of the CLI.
To actually install the new version of the CLI, please see the docs and the releases page. Note that some changes listed here are optional (and will be explicitly marked as such). If you ever run into issues while upgrading, please feel free to submit an issue.
Note
This document is empty for now, and will be until v0.2.0 of the CLI is released with actual breaking changes. Check back later :)
About
bevy_lint
is a custom linter for the Bevy game engine, similar to Clippy.
This is an unofficial community project, hacked upon by the Bevy CLI working group until it is eventually upstreamed into the main Bevy Engine organization. Pardon our rough edges, and please consider submitting an issue or reaching out in the Bevy Discord if you run into trouble!
Installation
CLI
The CLI supports automatically installing the latest released version of the linter if you do not have it installed already. Make sure you have the CLI first, then simply run the lint
subcommand:
bevy lint
The CLI will prompt you if you wish to install the linter. Type y
and press enter to accept:
warning: failed to run bevy_lint, trying to find automatic fix...
`bevy_lint` is missing, should I install it for you? [y/n]
If you want to auto-confirm the prompt, you may pass --yes
to the command. Note that if you are installing the linter in CI, you may wish to use the dedicated Github Action instead:
bevy lint --yes
Manual
bevy_lint
depends on a pinned nightly version of Rust with the rustc-dev
Rustup component. This is because bevy_lint
uses internal rustc
crates that can only be imported with the permanently-unstable rustc_private
feature. You can refer to the compatibility table to see which version of the linter requires which toolchain.
You can install the toolchain with:
rustup toolchain install $TOOLCHAIN_VERSION \
--component rustc-dev \
--component llvm-tools-preview
For example, you would replace $TOOLCHAIN_VERSION
with nightly-2024-11-14
if you were installing bevy_lint
v0.1.0, based on the compatibility table. Please be aware that you must keep this toolchain installed for bevy_lint
to function1.
Once you have the toolchain installed, you can compile and install bevy_lint
through cargo
:
rustup run $TOOLCHAIN_VERSION cargo install \
--git https://github.com/TheBevyFlock/bevy_cli.git \
--tag $TAG \
--locked \
bevy_lint
Make sure to replace $TOOLCHAIN_VERSION
and $TAG
in the above command. The tag for a specific release can be found in the releases tab. For example, the tag for v0.1.0 is lint-v0.1.0
.
Uninstall
If you wish to uninstall the linter at any time, you may use Cargo and Rustup to do so:
cargo uninstall bevy_lint
rustup toolchain uninstall $TOOLCHAIN_VERSION
Upgrade
To upgrade to a newer version of the linter, first uninstall it then follow the CLI or manual installation instructions.
-
bevy_lint
imports internalrustc
libraries in order to hook into the compiler process. These crates are stored in a dynamic library that is installed with therustc-dev
component and loaded bybevy_lint
at runtime. Uninstalling the nightly toolchain would remove this dynamic library, causingbevy_lint
to fail. ↩
Usage
bevy_lint
has the same API as the cargo check
command:
bevy_lint --help
If you have the prototype Bevy CLI installed, the linter is also available through the lint
subcommand:
bevy lint --help
Note
bevy_lint
checks your code with the nightly toolchain it was installed with, meaning you do have access to unstable features when it is called. This is best used when detectingbevy_lint
.
Toggling Lints in Cargo.toml
You can set the default level for lints in a Cargo.toml
using the [package.metadata.bevy_lint]
table:
[package.metadata.bevy_lint]
# Make the `missing_reflect` lint a warning.
missing_reflect = "warn"
# Make the `panicking_methods` lint an error that cannot be `#[allow(...)]`d.
panicking_methods = { level = "forbid" }
You can configure lints for an entire workspace by using [workspace.metadata.bevy_lint]
in the root Cargo.toml
instead:
[workspace.metadata.bevy_lint]
# Enable the entire `pedantic` lint group, and make them all warnings.
pedantic = "warn"
Crate lint configuration is merged with workspace lint configuration, with crate lint configuration taking priority.
Note that unlike with Cargo's [lints]
table, the priority
field is not supported. Furthermore, if you wish to use #[allow(...)]
and related attributes inside your code for Bevy-specific lints, please see Toggling Lints in Code.
Detecting bevy_lint
The linter passes --cfg bevy_lint
when it checks your code, allowing you to detect it:
// Conditionally include this function only when `bevy_lint` is used.
#[cfg(bevy_lint)]
fn foo() {
// ...
}
// Conditionally add an attribute only when `bevy_lint` is used.
#[cfg_attr(bevy_lint, ...)]
struct Foo;
If you use this, you may also need to register bevy_lint
as a valid cfg
flag in your Cargo.toml
:
[lints.rust]
unexpected_cfg = { level = "warn", check-cfg = ["cfg(bevy_lint)"] }
Registering bevy
as a Tool
When you run bevy_lint
on a project, rustc
knows an exact list of all bevy::
lints registered. With this it can detect that bevy::missing_reflect
is valid and bevy::uh_oh
isn't, and emit a corresponding warning.
When you run normal cargo check
, however, it does not know about any bevy::
lints. In order to avoid erroring on all usages of bevy::
, but to still provide good diagnostics on typos, the #![register_tool(...)]
attribute was introduced.
// Note that this is nightly-only. We'll get to that in a second!
#![register_tool(bevy)]
Using #![register_tool(bevy)]
tells the compiler that bevy
is a valid name in attributes, even if it does not know what bevy
is.1 When cargo check
now runs over a project with #[warn(bevy::lint_name)]
, it will simply skip it instead of emitting an error. (But running bevy_lint
will still detect and check this attribute as normal.)
If you wish to refer to a bevy
lint at all in your code (usually to toggle it), you must add #![register_tool(bevy)]
to each crate root. Unfortunately, #![register_tool(...)]
is currently unstable, meaning you need to add #![feature(register_tool)]
to your code as well. This isn't an issue if you detect when bevy_lint
is enabled, since it is guaranteed to check your code using nightly Rust.
// When `bevy_lint` is used, enable the `register_tool` feature and register `bevy` as a tool.
#![cfg_attr(bevy_lint, feature(register_tool), register_tool(bevy))]
Tip
If your project already uses nightly Rust, you can forego the
#[cfg_attr(bevy_lint, ...)]
attributes and write#![feature(register_tool)]
and#![register_tool(bevy)]
directly! Cool!
-
If you've ever used
#[rustfmt::skip]
in your code, this is howrustc
avoids erroring on it. However unlike thebevy
namespace,rustfmt
is registered automatically without a need for#![register_tool(rustfmt)]
due to it being an official tool. ↩
Toggling Lints in Code
It is possible to set lint levels on a case-by-case basis inside your code, but it requires a few more steps than setting the levels for the entire crate in Cargo.toml
. First, you must register bevy
as a tool. Not doing so will cause #[allow(bevy::lint_name)]
and related attributes to fail to compile.
Once bevy
is registered, you can toggle lints throughout your code, as long as they too are behind #[cfg_attr(bevy_lint, ...)]
:
#![cfg_attr(bevy_lint, feature(register_tool), register_tool(bevy))]
// Enable the `pedantic` lint group, which is off by default.
#![cfg_attr(bevy_lint, warn(bevy::pedantic))]
// Deny panicking Bevy methods in this system when a non-panicking alternatives exist.
#[cfg_attr(bevy_lint, deny(bevy::panicking_methods))]
fn my_critical_system(world: &mut World) {
// ...
}
There are several other ways to toggle lints, although some have varying levels of support:
Method | Support | Additional Information |
---|---|---|
[package.metadata.bevy_lint] in Cargo.toml | ✅ | See Toggling Lints in Cargo.toml . |
[workspace.metadata.bevy_lint] in Cargo.toml | ✅ | See Toggling Lints in Cargo.toml . |
#[allow(...)] and related | ✅ | Must be behind #[cfg_attr(bevy_lint, ...)] on stable Rust. |
[lints.bevy] in Cargo.toml | ⚠️ | Nightly only because #[register_tool(bevy)] must always be enabled. Prints a warning each time cargo is run. |
[workspace.lints.bevy] in Cargo.toml | ⚠️ | Same as [lints.bevy] . |
RUSTFLAGS="-A bevy::lint" | ❌ | RUSTFLAGS applies to dependencies, but they do not have #[register_tool(bevy)] . |
Compatibility
bevy_lint Version | Rust Version | Rustup Toolchain | Bevy Version |
---|---|---|---|
0.4.0-dev | 1.88.0 | nightly-2025-04-03 | 0.16 |
0.3.0 | 1.88.0 | nightly-2025-04-03 | 0.16 |
0.2.0 | 1.87.0 | nightly-2025-02-20 | 0.15 |
0.1.0 | 1.84.0 | nightly-2024-11-14 | 0.14 |
The Rust version in the above table specifies what version of the Rust language can be compiled with bevy_lint
. Code written for a later version of Rust may not compile. (This is not usually an issue, though, because bevy_lint
's Rust version is kept 1 to 2 releases ahead of stable Rust.)
The Rustup toolchain specifies which toolchain must be installed in order for bevy_lint
to be installed and used. Please see the installation section for more info.
The Bevy version is a range of Bevy versions that bevy_lint
has been tested with and is guaranteed to work. Newer or older releases may not be linted correctly and may cause the linter to crash. (If this does happen for you, please consider submitting a bug report!)
Github Actions
bevy_lint
provides an action to conveniently install the linter in CI:
# Replace `lint-vX.Y.Z` with the tag of the version installed, such as `lint-v0.3.0`.
- name: Install `bevy_lint`
uses: TheBevyFlock/bevy_cli/bevy_lint@lint-vX.Y.Z
- name: Run `bevy_lint`
run: bevy_lint --workspace
You may install the unstable, bleeding-edge version from the main
branch:
- name: Install `bevy_lint`
uses: TheBevyFlock/bevy_cli/bevy_lint@main
Note that this action overrides the default toolchain and configures it to be the nightly version specified in the compatibility table. If you previously installed another Rustup toolchain, you may wish to reconfigure it to be the default:
# Sets the default toolchain to be stable Rust.
- name: Install stable Rust
uses: dtolnay/rust-toolchain@stable
# Overrides the default toolchain to be nightly Rust.
- name: Install `bevy_lint`
uses: TheBevyFlock/bevy_cli/bevy_lint@lint-vX.Y.Z
# Resets the default toolchain back to stable Rust.
- name: Configure the default Rust toolchain
run: rustup default stable
Important
The action is only available for versions v0.3.0 and onward. v0.2.0 and v0.1.0 will not work, however you may emulate it by manually running the installation commands in your workflow.
Changelog
All notable user-facing changes to the Bevy Linter will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
All Changes: lint-v0.3.0...main
v0.3.0 - 2025-04-30
All Changes: lint-v0.2.0...lint-v0.3.0
Added
- Lint
iter_current_update_events
tosuspicious
(#314) - Lint
unconventional_naming
tostyle
(#345)plugin_not_ending_in_plugin
has been merged into this new lint.
- A Github Action to automatically install the linter (#380)
Changed
- The linter now supports Bevy 0.16, but no longer supports Bevy 0.15 (#323)
- Bumped nightly toolchain to
nightly-2025-04-03
(#373)- The linter now supports Rust 1.88.0.
- Moved lints into submodules for their corresponding lint groups (#321)
- This makes it easier to see what lint group a lint is under in the documentation. For example, in v0.2.0 if you wanted to view the
insert_unit_bundle
lint you would go tobevy_lint::lints::insert_unit_bundle
, but in v0.3.0 you would go tobevy_lint::lints::suspicious::insert_unit_bundle
. This signals thatinsert_unit_bundle
is asuspicious
lint.
- This makes it easier to see what lint group a lint is under in the documentation. For example, in v0.2.0 if you wanted to view the
- Moved lint group docs from
bevy_lint::groups
to their associatedbevy_lint::lints
submodules (#328) - Code generated from external macros are no longer linted (#263)
- External macros are macros that are defined in a separate crate from the one being linted. The output of these macros is skipped for all lints, as it was previously impossible to fix the warnings without an
#[allow(...)]
attribute.
- External macros are macros that are defined in a separate crate from the one being linted. The output of these macros is skipped for all lints, as it was previously impossible to fix the warnings without an
missing_reflect
now emits machine-applicable suggestions if all fields in a type implementPartialReflect
(#389)
Removed
- Lint
plugin_not_ending_in_plugin
(#345)- This lint has been merged into the new
unconventional_naming
lint.
- This lint has been merged into the new
Fixed
main_return_without_appexit
no longer fires if theAppExit
is used (#346)- The goal of the lint is to encourage the
AppExit
to be handled, although returning it frommain()
is just one solution. This fix prevents the lint from yelling at you if you choose to handle it a different way, or simply choose to discard it withlet _ = app.run();
.
- The goal of the lint is to encourage the
- Fixed the Rust version in the compatibility table for v0.2.0 (#363)
v0.2.0 - 2025-03-19
All Changes: lint-v0.1.0...lint-v0.2.0
Added
- Lint
borrowed_reborrowable
topedantic
(#164) - Lint
insert_unit_bundle
tosuspicious
(#210) - Lint configuration in
Cargo.toml
(#251) - Support for
bevy_lint --version
(#257) - Support for qualified method syntax in several lints (#253)
- Lint
duplicate_bevy_dependencies
(#280)
Changed
- The linter now supports Bevy 0.15, but no longer supports Bevy 0.14 (#191)
- Eventually the linter will support multiple versions of Bevy at the same time. Please see #138 for more information.
- Bumped nightly toolchain to
nightly-2025-02-20
(#278) - Lowered
zst_query
lint fromrestriction
tonursery
(#261)zst_query
does not respectQueryData::Item
, meaning it is broken for queries likeHas<T>
andAnyOf<T>
. Please see #279 for more information.
- Merged
panicking_query_methods
andpanicking_world_methods
into a single lint:panicking_methods
(#271)
Fixed
rustc_driver.dll
not found on Windows (#281)bevy_lint
should now work on Windows, as it was previously broken by this bug.
v0.1.0 - 2024-11-17
All Changes: lint-v0.1.0
Added
- Lint
main_return_without_appexit
topedantic
(#84) - Lint
insert_event_resource
tosuspicious
(#86) - Lint groups
correctness
,suspicious
,complexity
,performance
,style
,pedantic
,restriction
, andnursery
(#98)- These are based directly on Clippy's Lint Groups.
- Lints
panicking_query_methods
andpanicking_world_methods
torestriction
(#95) - Lint
plugin_not_ending_in_plugin
tostyle
(#111) - Lint
missing_reflect
torestriction
(#139) - Lint
zst_query
torestriction
(#168)
Migration Guide
Occasionally changes are made to the Bevy Linter that may break existing projects, or majorly change how it is intended to be used. This document provides a guide recommending how to upgrade your existing project to a newer version of the linter.
To actually install the new version of the linter, please see the docs and the releases page. Note that some changes listed here are optional (and will be explicitly marked as such). If you ever run into issues while upgrading, please feel free to submit an issue.
v0.2.0 to v0.3.0
Bevy 0.16 Support
The linter now supports Bevy 0.16, but no longer supports Bevy 0.15. You may still be able to run the linter successfully on Bevy 0.15 projects, but no guarantee is made on stability or correctness.
To migrate your code base to Bevy 0.16, please see the release post and migration guide.
Bumped Nightly Toolchain to nightly-2025-04-03
The linter now requires the nightly-2025-04-03
Rustup toolchain to be installed, instead of nightly-2025-02-20
. The supported Rust language version is now 1.88.0 instead of the previous 1.87.0.
For more information on how to install this toolchain and its required components, please see the linter docs.
Removed plugin_not_ending_in_plugin
The plugin_not_ending_in_plugin
lint has been removed in favor of the new unconventional_naming
lint. unconventional_naming
offers the same checks as plugin_not_ending_in_plugin
, but now supports checking SystemSet
s as well.
If you reference plugin_not_ending_in_plugin
in your code, a new warning will be emitted suggesting you rename it to unconventional_naming
.
Created Github Action to install bevy_lint
(Optional)
If you were manually installing bevy_lint
in CI by following the installation instructions, you can now replace it with the new action:
- name: Install `bevy_lint`
uses: TheBevyFlock/bevy_cli/bevy_lint@lint-v0.3.0
- name: Run `bevy_lint`
run: bevy_lint --workspace
v0.1.0 to v0.2.0
Bevy 0.15 Support
The linter now supports Bevy 0.15, but no longer supports Bevy 0.14. You may still be able to run the linter successfully on Bevy 0.14 projects, but no guarantee is made on stability or correctness.
To migrate your code base to Bevy 0.15, please see the release post and migration guide.
Bumped Nightly Toolchain to nightly-2025-02-20
The linter now requires the nightly-2025-02-20
Rustup toolchain to be installed, instead of nightly-2024-11-14
. The supported Rust language version is now 1.87.01 instead of the previous 1.84.0.
For more information on how to install this toolchain and its required components, please see the linter docs.
Merged panicking_query_methods
and panicking_world_methods
The panicking_query_methods
and panicking_world_methods
lints have been merged into a single lint: panicking_methods
. This new lint has the same functionality as the two previous lints combined.
#![allow(unused)] fn main() { // v0.1.0 #[cfg_attr(bevy_lint, deny(bevy::panicking_query_methods))] fn critical_system(query: Query<&MyComponent>) { // ... } // v0.2.0 #[cfg_attr(bevy_lint, deny(bevy::panicking_methods))] fn critical_system(query: Query<&MyComponent>) { // ... } }
Lowered zst_query
from restriction
to nursery
A critical bug was found in zst_query
where it would incorrectly warn on certain queries that do actually query data, such as Has<T>
and AnyOf<T>
. As such, it has been temporarily moved to the nursery
lint group, meaning that it is marked as unstable and may be removed.
Until #279 is fixed, it is recommended to remove references of this lint from your project.
Lint Configuration in Cargo.toml
(Optional)
It is now possible to configure lints in a crate's Cargo.toml
instead of directly in its code.
#![allow(unused)] #![cfg_attr(bevy_lint, feature(register_tool), register_tool(bevy))] fn main() { // You can delete these attributes from your crate root. #![cfg_attr(bevy_lint, warn(bevy::pedantic))] #![cfg_attr(bevy_lint, deny(bevy::panicking_methods))] }
# And add them to `Cargo.toml` instead.
[package.metadata.bevy_lint]
pedantic = "warn"
panicking_methods = "deny"
Lint levels specified in Cargo.toml
will be applied for the entire crate, but can still be overridden in your code.
How to Release the CLI
Kick-off Pull Request
- Review the changelog (
CHANGELOG.md
) and ensure that all notable changes have been documented. - Replace
Unreleased
heading with the version with the formatvX.Y.Z - YYYY-MM-DD
. - Update the
**All Changes**
link to compare frommain
to the new tagcli-vX.Y.Z
. (E.g.cli-v0.1.0...main
tocli-v0.1.0...cli-v0.2.0
.) - Review the migration guide (
MIGRATION.md
) and ensure all breaking / significant changes from the previous version are documented. - Remove the
-dev
suffix from the version inCargo.toml
.- Please ensure that
Cargo.lock
also updates!
- Please ensure that
- Commit your changes and open a pull request.
- Merge the PR once a core Bevy maintainer approves it with no outstanding issues from other contributors.
- This starts the release process, enacting a freeze on all other changes until the release has finished. While maintainers need to be aware of this so they do not merge PRs during this time, the release process should take less than an hour, so it's unlikely to ever be an issue.
Release on Github
- Create a new Github release.
- Set the tag to
cli-vX.Y.Z
. - Set the title to
`bevy_cli` - vX.Y.Z
. - Paste and fill out the following template into the release documentation:
<!-- One-sentence summary of changes. What awesome features can we spotlight? What critical bugs were fixed? -->
You can find the live documentation for this release [here](https://thebevyflock.github.io/bevy_cli/cli/index.html). You may also be interested in [the changelog] and [the migration guide].
<!-- Make sure to update the tags in these links to point to the correct version. -->
[the changelog]: https://github.com/TheBevyFlock/bevy_cli/blob/cli-vX.Y.Z/CHANGELOG.md
[the migration guide]: https://github.com/TheBevyFlock/bevy_cli/blob/cli-vX.Y.Z/MIGRATION.md
> [!WARNING]
>
> This is an unofficial community project, hacked upon by the Bevy CLI working group until it is eventually upstreamed into the main [Bevy Engine organization](https://github.com/bevyengine). Pardon our rough edges, and please consider [submitting an issue](https://github.com/TheBevyFlock/bevy_cli/issues) if you run into trouble!
You can install the precompiled CLI using `cargo-binstall`:
<!-- Update `X.Y.Z` with the correct version. -->
```sh
cargo binstall --git https://github.com/TheBevyFlock/bevy_cli --version X.Y.Z --locked bevy_cli
```
You may also compile the CLI yourself with `cargo install`:
<!-- Update `cli-vX.Y.Z` with the correct tag. -->
```sh
cargo install --git https://github.com/TheBevyFlock/bevy_cli --tag cli-vX.Y.Z --locked bevy_cli
```
- Check the pre-release box if this is an alpha release, then click "Save draft".
- Run the "Build CLI" workflow, and make sure to check the "Upload to release" box.
- Ensure that the workflow has successfully uploaded all executables to the draft release, then press "Publish release"!
- Announce the release on Discord and other social medias. Congrats!
Post-Release
- Add a new unreleased section to the top of the changelog (
CHANGELOG.md
) from the following template:
## Unreleased
<!-- Update `cli-vX.Y.Z` in the link to point to the latest release tag. -->
**All Changes**: [`cli-vX.Y.Z...main`](https://github.com/TheBevyFlock/bevy_cli/compare/cli-vX.Y.Z...main)
- Bump the version in
Cargo.toml
to the next-dev
version, and ensureCargo.lock
also updates. - Commit your changes and open a pull request.
- Merge the PR once it has been approved, unblocking the feature freeze.
About
Thank you for your interest in contributing to bevy_lint
! Please feel free to take a peek at any of the articles in the table of context. These docs follow the Diátaxis documentation system1, meaning pages are organized based on how they're meant to be read.
- Tutorial: Practice by doing something.
- How-to Guides: Learn how to solve a specific problem.
- Reference: Refer to technical knowledge while working.
- Explanation: Learn the reasons behind certain decisions.
Important
This is the documentation for contributing to
bevy_lint
. If you want to learn how to usebevy_lint
instead, please take a look at the user guide.
Additional Resources
⭐️ = Recommended Reading
- Rust Compiler Development Guide
- Debugging the compiler (not all sections apply)
- Overview of the compiler
- Queries: demand-driven compilation
- Memory Management in Rustc
- ⭐️ The HIR
rustc_driver
andrustc_interface
- ⭐️ Errors and Lints
- ⭐️ The
ty
module: representing types - Glossary
- Code Index
- Humor in Rust (not actually relevant)
rustc
API Docs- Clippy Development
-
You may also know Diátaxis as the Divio documentation system. Diátaxis was developed while the author was working at Divio. ↩
Tutorial
A tutorial is an experience that takes place under the guidance of a tutor. A tutorial is always learning-oriented.
A tutorial is a practical activity, in which the student learns by doing something meaningful, towards some achievable goal.
A tutorial serves the user's acquisition of skills and knowledge - their study. Its purpose is not to help the user get something done, but to help them learn.
A tutorial in other words is a lesson.
How-To
How-to guides are directions that guide the reader through a problem or towards a result. How-to guides are goal-oriented.
A how-to guide helps the user get something done, correctly and safely; it guides the user’s action.
It's concerned with work - navigating from one side to the other of a real-world problem-field.
Setup Your Editor
There can be a few extra steps required to get code completion and syntax highlighting setup with your editor.
Note
Can't find your editor here? Open an issue here! The
rustc
Development Guide may be a useful starting point, though several points won't apply tobevy_lint
.
VSCode
bevy_lint
works out-of-the-box with VSCode's rust-analyzer
extension. The settings are specified in .vscode/settings.json
:
{
// Enables Rust-Analyzer support for `rustc` crates.
"rust-analyzer.rustc.source": "discover",
// Show dependency types while fuzzy searching, including types from `rustc` crates.
"rust-analyzer.workspace.symbol.search.scope": "workspace_and_dependencies",
}
Neovim
First, setup rust-analyzer
by following the instructions here. Next, install the neoconf.nvim
plugin, which will automatically import the settings from .vscode/settings.json
.
RustRover
As of December 2024, RustRover and the JetBrains Rust plugin do not work with rustc
's internal crates. If you manage to get it working, make sure to submit an issue!
Work with Types
Note
This document assumes you are working with
ty::Ty
, notrustc_hir::Ty
, unless explicitly stated otherwise.
Getting the Type of an Expression
It is possible to get the type of an expression (Expr
) through TypeckResults
:
#![allow(unused)] fn main() { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { let ty = cx.typeck_results().expr_ty(expr); } }
Peeling References
Often you have the type that may be behind one or more references, such as &&str
or *mut [T]
, but you need to extract the underlying type (str
and [T]
in this case). You can do this by "peeling" references:
#![allow(unused)] fn main() { let peeled_ty = ty.peel_refs(); }
See Ty::peel_refs()
for more information.
Getting the Adjusted Type of an Expression
The Rust compiler occasionally makes adjustments to types in order to support automatic dereferencing and type coercion. TypeckResults::expr_ty()
ignores these adjustments, returning the original type. Sometimes this isn't desired, as you may want the adjusted type, in which case you should use TypeckResults::expr_ty_adjusted()
instead:
#![allow(unused)] fn main() { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { let ty = cx.typeck_results().expr_ty_adjusted(expr); } }
For example, you may be writing a lint to check when a user calls str::contains()
. In order to catch the most cases, you want to also check for method calls on types that dereference into str
, such as String
and Box<str>
. expr_ty_adjusted()
lets you treat String
and Box<str>
as str
:
#![allow(unused)] fn main() { // `expr_ty()` is `&str`, `expr_ty_adjusted()` is `&str`. let a = "Hello, world!".contains("Hello"); // `expr_ty()` is `String`, `expr_ty_adjusted()` is `&str`. let b = String::from("Hello, world!").contains("Hello"); // `expr_ty()` is `Box<&str>`, `expr_ty_adjusted()` is `&str`. let c = Box::new("Hello, world!").contains("Hello"); }
For more information, see Adjustment
, Type coercions, and Method lookup.
Checking for a Specific Type
Often you have a Ty
, and want to check if it matches a specific hardcoded type, such as Bevy's App
. You can do this with clippy_utils
's match_type()
function:
#![allow(unused)] fn main() { use clippy_utils::ty::match_type; // The absolute path to `App`'s definition. const APP: [&str; 3] = ["bevy_app", "app", "App"]; if match_type(cx, ty, &APP) { // ... } }
All path constants are defined in paths.rs
. If you add a new constant, place it there.
Important
bevy_app::app
is a private module, but we still have to refer to it by name becausestruct App
is withinbevy_app/src/app.rs
. Do not be tricked by re-exported types, such asbevy::prelude::App
!
Getting ty::Ty
from rustc_hir::Ty
Often you'll have an rustc_hir::Ty
, but you need ty::Ty
. This is a process known as lowering, and it is accomplished through the ty_from_hir_ty()
function:
#![allow(unused)] fn main() { use clippy_utils::ty::ty_from_hir_ty; fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &rustc_hir::Ty<'tcx, AmbigArg>) { let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()); } }
Also note that this conversion is one-directional and cannot be easily reversed. While rustc_hir::Ty
s are associated with a specific span of code, ty::Ty
s are not. For more information, please see rustc_hir::Ty
vs ty::Ty
from the rustc
Dev Guide.
Parse Method Calls
A method call is a kind of expression, and can come in both receiver and qualified form:
#![allow(unused)] fn main() { // Both of these do the same thing! receiver.method(args); Struct::method(&receiver, args); }
In order to parse a method call, you must first have an Expr
. In this case we'll first implement LateLintPass
's check_expr()
method, but you can get an Expr
through several other means:
#![allow(unused)] fn main() { impl<'tcx> LateLintPass<'tcx> for MyLintPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // ... } } }
Once you have an Expr
, you can parse method calls with the MethodCall
utility:
#![allow(unused)] fn main() { use crate::utils::hir_parse::MethodCall; fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // Extract a `MethodCall` from the `Expr` if it is a method call. if let Some(MethodCall { receiver, args, .. }) = MethodCall::try_from(cx, expr) { // ... } } }
MethodCall::try_from()
returns an Option
, and will only be Some
if the expression was actually a method call. Take a look at MethodCall
's fields to see what properties are available.
Caution
Although ExprKind::MethodCall
does exist, it does not support qualified method syntax. You should avoid it if possible.
Release bevy_lint
Kick-off Pull Request
- Review the changelog (
bevy_lint/CHANGELOG.md
) and ensure that all notable changes have been documented. - Replace
Unreleased
heading with the version with the formatvX.Y.Z - YYYY-MM-DD
. - Update the
**All Changes**
link to compare frommain
to the new taglint-vX.Y.Z
. (E.g.lint-v0.1.0...main
tolint-v0.1.0...lint-v0.2.0
.) - Review the migration guide (
bevy_lint/MIGRATION.md
) and ensure all breaking / significant changes from the previous version are documented. - Remove the
-dev
suffix from the version inCargo.toml
and the compatibility table inbevy_lint/README.md
.- Please ensure that
Cargo.lock
also updates!
- Please ensure that
- Replace
--branch main
inaction.yml
with--tag lint-vX.Y.Z
.- The
linter-action.yml
workflow may fail as the tag does not exist yet. This is fine!
- The
- Commit all of these changes and open a pull request.
- Merge the PR once a core Bevy maintainer approves it with no outstanding issues from other contributors.
- This starts the release process, enacting a freeze on all other changes until the release has finished. While maintainers need to be aware of this so they do not merge PRs during this time, the release process should take less than an hour, so it's unlikely to ever be an issue.
Release on Github
- Create a new Github release.
- Set the tag to
lint-vX.Y.Z
. - Set the title to
`bevy_lint` - vX.Y.Z
- Paste and fill out the following template into the release description:
<!-- One-sentence summary of changes. What awesome features can we spotlight? What critical bugs were fixed? -->
You can find the live documentation for this release [here](https://thebevyflock.github.io/bevy_cli/linter/index.html). You may also be interested in [the changelog] and [the migration guide].
<!-- Make sure to update the tags in these links to point to the correct version. -->
[the changelog]: https://github.com/TheBevyFlock/bevy_cli/blob/lint-vX.Y.Z/bevy_lint/CHANGELOG.md
[the migration guide]: https://github.com/TheBevyFlock/bevy_cli/blob/lint-vX.Y.Z/bevy_lint/MIGRATION.md
> [!WARNING]
>
> This is an unofficial community project, hacked upon by the Bevy CLI working group until it is eventually upstreamed into the main [Bevy Engine organization](https://github.com/bevyengine). Pardon our rough edges, and please consider [submitting an issue](https://github.com/TheBevyFlock/bevy_cli/issues) if you run into trouble!
<!-- You can refer to the compatibility table in `bevy_lint/README.md` for the following two values. -->
This release uses the <!-- `nightly-YYYY-MM-DD` --> toolchain, based on Rust <!-- 1.XX.Y -->. You can install it from Git with the following commands:
<!-- Update `nightly-YYYY-MM-DD` and `lint-vX.Y.Z` in the following code block. -->
```bash
rustup toolchain install nightly-YYYY-MM-DD \
--component rustc-dev \
--component llvm-tools-preview
rustup run nightly-YYYY-MM-DD cargo install \
--git https://github.com/TheBevyFlock/bevy_cli.git \
--tag lint-vX.Y.Z \
--locked \
bevy_lint
```
<!-- Paste the changelog for this release here. Make sure to include the "All Changes" link. :) -->
- Check the pre-release box if this is an alpha release, then click "Publish release"!
- Announce the release on Discord! Congrats!
Post-Release
- Add a new unreleased section to the top of the changelog (
bevy_lint/CHANGELOG.md
) from the following template:
## [Unreleased]
<!-- Update `lint-vX.Y.Z` in the link to point to the latest release tag. -->
**All Changes**: [`lint-vX.Y.Z...main`](https://github.com/TheBevyFlock/bevy_cli/compare/lint-vX.Y.Z...main)
- Bump the version in
Cargo.toml
to the next-dev
version, and ensureCargo.lock
also updates. - Add a new row to the compatibility table for the new
-dev
version inREADME.md
. - Replace
--tag lint-vX.Y.Z
inaction.yml
with--branch main
. - Commit all of these changes and open a pull request.
- Merge the PR after it has been approved, unblocking frozen pull requests.
Upgrade the Rust Toolchain
bevy_lint
matches nightly Rust versions with clippy_utils
. A new version of clippy_utils
is released with each version of Rust, which bevy_lint
should keep up to date with.
-
Go to
clippy_utils
's page on crates.io and find the nightly toolchain it requires. For example:This crate is only guaranteed to build with this nightly toolchain:
nightly-2025-01-09
-
Change the
channel
field inrust-toolchain.toml
to the version specified byclippy_utils
. -
Update the compatibility table for the latest
-dev
version. -
Increase the version of
clippy_utils
inCargo.toml
to the latest version. -
Change the two occurrences of the toolchain in
action.yml
to the new version.
Once you've finished upgrading the Rust toolchain and clippy_utils
, there are a few extra steps that can verify bevy_lint
still functions the same.
-
Read over the release notes for potentially breaking changes.
-
Skim through diff.rs for
clippy_utils
to see if anything the linter uses may have changed.clippy_utils
doesn't provide a user-facing changelog, unfortunately. You may find the Git history useful, though!
-
Verify you've installed the latest pinned Rust toolchain. If you use Rustup, it should be automatically installed the first time you run
rustc
orcargo
in the workspace.rustc --version
-
Test that the linter still compiles and passes all tests.
cargo clean cargo build cargo test
-
After opening the pull request, verify that the
linter-action.yml
workflow passes in CI.
Reference
Reference guides are technical descriptions of the machinery and how to operate it. Reference material is information-oriented.
Reference material contains propositional or theoretical knowledge that a user looks to in their work.
The only purpose of a reference guide is to describe, as succinctly as possible, and in an orderly way. Whereas the content of tutorials and how-to guides are led by needs of the user, reference material is led by the product it describes.
Lint Module Docs
All lints, which can be found here, place their documentation in their module. For example, missing_reflect
's docs are in src/lints/missing_reflect.rs
. These docs must adhere to the following format:
A single sentence description of what this lint checks for.
In the rare case this needs to be elaborated, an optional paragraph beneath the first sentence is
allowed. Use this to go into more detail on what is checked for, as well as what not is checked
for.
# Motivation
One to several paragraphs describing why this lint exists. For example: does this lint help catch
slow code, or does it suggest a more idiomatic version? Try to motivate why a user may want to
enable this lint.
Be careful to only answer _why_ this lint exists, not _what_ it does or _how_ it works. That is the
responsibility of the extended description.
# Known Issues
This is an optional section that describes what false negatives and false positives this lint may
have. (Usually to justify why a lint is in the `nursery` group, though not always.) If possible,
make sure to link to the issue in the
[issue tracker](https://github.com/TheBevyFlock/bevy_cli/issues) so users can comment on it.
# Example
```
// A snippet of code that would cause the lint to trigger. If a specific line would cause the lint,
// make sure to point it out with a comment.
// Note how this variable is not used:
let x = 10;
// If bodies of functions are not relevant to the lint, use `// ...` to signal that there may be
// other code there.
fn foo() {
// ...
}
```
Use instead:
```
// The second code snippet should be a "fixed" version of the original. Comments from the original
// do not need to be copied over, but it may be useful to add a note on how or why the lint was
// fixed a specific way.
// `_x` will silence the lint, but `_` also works. You can also delete the line, if you truly do
// not want `10`.
let _x = 10;
fn foo() {
// ...
}
```
If you wish to elaborate further on how to fix the lint or supply further examples, you may do so
here. If this is a Cargo lint, switch out the Rust code block with a TOML one for `Cargo.toml`.
Macro-Generated Code
When a developer uses a macro from a 3rd-party crate, it generates code that the developer cannot easily change or fix. Macro-generated code will still be linted, but if that code has any issues the developer cannot do anything to fix it beyond adding an #[allow(...)]
attribute.
Because of this, all bevy_lint
lint passes should skip code generated by an external macro. This can be done with Span::in_external_macro()
:
#![allow(unused)] fn main() { impl<'tcx> LateLintPass<'tcx> for MyLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // Do not lint this expression if it was generated by an external macro. if expr.span.in_external_macro(cx.tcx.sess.source_map()) { return; } // ... } } }
For more information, please see Clippy's docs on macros, the issue about macros, and the PR that first incorporated these checks.
Coding Conventions and Best Practices
This document contains a list of conventions that bevy_lint
's code follows to ensure consistency across the project. Beyond this document, the project uses Clippy, rustfmt
, and typos
in CI, and it follows the majority of the Rust API Guidelines.
Avoid HasSession
HasSession
is a trait in clippy_utils
intended to make their API more friendly. HasSession
provides the sess()
method on TyCtxt
, LateContext
, and a few other types. HasSession::sess()
should not be used within bevy_lint
because Session
is trivial to get without it, and HasSession
requires an extra import.
#![allow(unused)] fn main() { use clippy_utils::source::HasSession; fn late_context<'tcx>(cx: LateContext<'tcx>) { let sess = cx.sess(); } fn ty_ctxt<'tcx>(tcx: TyCtxt<'tcx>) { let sess = tcx.sess(); } }
Use instead:
#![allow(unused)] fn main() { fn late_context<'tcx>(cx: LateContext<'tcx>) { let sess = cx.tcx.sess; } fn ty_ctxt<'tcx>(tcx: TyCtxt<'tcx>) { let sess = tcx.sess; } }
Explanation
Explanation is a discursive treatment of a subject, that permits reflection. Explanation is understanding-oriented.
Explanation deepens and broadens the reader’s understanding of a subject. It brings clarity, light and context.
The concept of reflection is important. Reflection occurs after something else, and depends on something else, yet at the same time brings something new - shines a new light - on the subject matter.
The perspective of explanation is higher and wider than that of the other three types. It does not take the user’s eye-level view, as in a how-to guide, or a close-up view of the machinery, like reference material. Its scope in each case is a topic - "an area of knowledge", that somehow has to be bounded in a reasonable, meaningful way.