Auto merge of #76549 - ehuss:lints-comments, r=wesleywiser
Auto-generate lint documentation. This adds a tool which will generate the lint documentation in the rustc book automatically. This is motivated by keeping the documentation up-to-date, and consistently formatted. It also ensures the examples are correct and that they actually generate the expected lint. The lint groups table is also auto-generated. See https://github.com/rust-lang/compiler-team/issues/349 for the original proposal. An outline of how this works: - The `declare_lint!` macro now accepts a doc comment where the documentation is written. This is inspired by how clippy works. - A new tool `src/tools/lint-docs` scrapes the documentation and adds it to the rustc book during the build. - It runs each example and verifies its output and embeds the output in the book. - It does a few formatting checks. - It verifies that every lint is documented. - Groups are collected from `rustc -W help`. I updated the documentation for all the missing lints. I have also added an "Explanation" section to each lint providing a reason for the lint and suggestions on how to resolve it. This can lead towards a future enhancement of possibly showing these docs via the `--explain` flag to make them easily accessible and discoverable.
This commit is contained in:
commit
b5f55b7e15
@ -1677,6 +1677,15 @@ version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||
|
||||
[[package]]
|
||||
name = "lint-docs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.3.4"
|
||||
|
@ -9,6 +9,7 @@ members = [
|
||||
"src/tools/compiletest",
|
||||
"src/tools/error_index_generator",
|
||||
"src/tools/linkchecker",
|
||||
"src/tools/lint-docs",
|
||||
"src/tools/rustbook",
|
||||
"src/tools/unstable-book-gen",
|
||||
"src/tools/tidy",
|
||||
|
@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// [1, 2, 3].into_iter().for_each(|n| { *n; });
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In the future, it is planned to add an `IntoIter` implementation for
|
||||
/// arrays such that it will iterate over *values* of the array instead of
|
||||
/// references. Due to how method resolution works, this will change
|
||||
/// existing code that uses `into_iter` on arrays. The solution to avoid
|
||||
/// this warning is to use `iter()` instead of `into_iter()`.
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a hard error
|
||||
/// in the future. See [issue #66145] for more details and a more thorough
|
||||
/// description of the lint.
|
||||
///
|
||||
/// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub ARRAY_INTO_ITER,
|
||||
Warn,
|
||||
"detects calling `into_iter` on arrays",
|
||||
|
@ -61,6 +61,23 @@ use tracing::{debug, trace};
|
||||
pub use rustc_session::lint::builtin::*;
|
||||
|
||||
declare_lint! {
|
||||
/// The `while_true` lint detects `while true { }`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// while true {
|
||||
///
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// `while true` should be replaced with `loop`. A `loop` expression is
|
||||
/// the preferred way to write an infinite loop because it more directly
|
||||
/// expresses the intent of the loop.
|
||||
WHILE_TRUE,
|
||||
Warn,
|
||||
"suggest using `loop { }` instead of `while true { }`"
|
||||
@ -102,6 +119,24 @@ impl EarlyLintPass for WhileTrue {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `box_pointers` lints use of the Box type.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(box_pointers)]
|
||||
/// struct Foo {
|
||||
/// x: Box<isize>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This lint is mostly historical, and not particularly useful. `Box<T>`
|
||||
/// used to be built into the language, and the only way to do heap
|
||||
/// allocation. Today's Rust can call into other allocators, etc.
|
||||
BOX_POINTERS,
|
||||
Allow,
|
||||
"use of owned (Box type) heap memory"
|
||||
@ -156,6 +191,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
|
||||
/// instead of `Struct { x }` in a pattern.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// struct Point {
|
||||
/// x: i32,
|
||||
/// y: i32,
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// let p = Point {
|
||||
/// x: 5,
|
||||
/// y: 5,
|
||||
/// };
|
||||
///
|
||||
/// match p {
|
||||
/// Point { x: x, y: y } => (),
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The preferred style is to avoid the repetition of specifying both the
|
||||
/// field name and the binding name if both identifiers are the same.
|
||||
NON_SHORTHAND_FIELD_PATTERNS,
|
||||
Warn,
|
||||
"using `Struct { x: x }` instead of `Struct { x }` in a pattern"
|
||||
@ -216,6 +281,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unsafe_code` lint catches usage of `unsafe` code.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unsafe_code)]
|
||||
/// fn main() {
|
||||
/// unsafe {
|
||||
///
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This lint is intended to restrict the usage of `unsafe`, which can be
|
||||
/// difficult to use correctly.
|
||||
UNSAFE_CODE,
|
||||
Allow,
|
||||
"usage of `unsafe` code"
|
||||
@ -303,6 +387,25 @@ impl EarlyLintPass for UnsafeCode {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_docs` lint detects missing documentation for public items.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(missing_docs)]
|
||||
/// pub fn foo() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This lint is intended to ensure that a library is well-documented.
|
||||
/// Items without documentation can be difficult for users to understand
|
||||
/// how to use properly.
|
||||
///
|
||||
/// This lint is "allow" by default because it can be noisy, and not all
|
||||
/// projects may want to enforce everything to be documented.
|
||||
pub MISSING_DOCS,
|
||||
Allow,
|
||||
"detects missing documentation for public members",
|
||||
@ -528,6 +631,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_copy_implementations` lint detects potentially-forgotten
|
||||
/// implementations of [`Copy`].
|
||||
///
|
||||
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(missing_copy_implementations)]
|
||||
/// pub struct Foo {
|
||||
/// pub field: i32
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Historically (before 1.0), types were automatically marked as `Copy`
|
||||
/// if possible. This was changed so that it required an explicit opt-in
|
||||
/// by implementing the `Copy` trait. As part of this change, a lint was
|
||||
/// added to alert if a copyable type was not marked `Copy`.
|
||||
///
|
||||
/// This lint is "allow" by default because this code isn't bad; it is
|
||||
/// common to write newtypes like this specifically so that a `Copy` type
|
||||
/// is no longer `Copy`. `Copy` types can result in unintended copies of
|
||||
/// large data which can impact performance.
|
||||
pub MISSING_COPY_IMPLEMENTATIONS,
|
||||
Allow,
|
||||
"detects potentially-forgotten implementations of `Copy`"
|
||||
@ -584,6 +715,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_debug_implementations` lint detects missing
|
||||
/// implementations of [`fmt::Debug`].
|
||||
///
|
||||
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(missing_debug_implementations)]
|
||||
/// pub struct Foo;
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Having a `Debug` implementation on all types can assist with
|
||||
/// debugging, as it provides a convenient way to format and display a
|
||||
/// value. Using the `#[derive(Debug)]` attribute will automatically
|
||||
/// generate a typical implementation, or a custom implementation can be
|
||||
/// added by manually implementing the `Debug` trait.
|
||||
///
|
||||
/// This lint is "allow" by default because adding `Debug` to all types can
|
||||
/// have a negative impact on compile time and code size. It also requires
|
||||
/// boilerplate to be added to every type, which can be an impediment.
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
Allow,
|
||||
"detects missing implementations of Debug"
|
||||
@ -640,6 +797,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `anonymous_parameters` lint detects anonymous parameters in trait
|
||||
/// definitions.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2015,compile_fail
|
||||
/// #![deny(anonymous_parameters)]
|
||||
/// // edition 2015
|
||||
/// pub trait Foo {
|
||||
/// fn foo(usize);
|
||||
/// }
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This syntax is mostly a historical accident, and can be worked around
|
||||
/// quite easily by adding an `_` pattern or a descriptive identifier:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo {
|
||||
/// fn foo(_: usize);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This syntax is now a hard error in the 2018 edition. In the 2015
|
||||
/// edition, this lint is "allow" by default, because the old code is
|
||||
/// still valid, and warning for all old code can be noisy. This lint
|
||||
/// enables the [`cargo fix`] tool with the `--edition` flag to
|
||||
/// automatically transition old code from the 2015 edition to 2018. The
|
||||
/// tool will switch this lint to "warn" and will automatically apply the
|
||||
/// suggested fix from the compiler (which is to add `_` to each
|
||||
/// parameter). This provides a completely automated way to update old
|
||||
/// code for a new edition. See [issue #41686] for more details.
|
||||
///
|
||||
/// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
|
||||
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
|
||||
pub ANONYMOUS_PARAMETERS,
|
||||
Allow,
|
||||
"detects anonymous parameters",
|
||||
@ -806,12 +1002,54 @@ impl EarlyLintPass for UnusedDocComment {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `no_mangle_const_items` lint detects any `const` items with the
|
||||
/// [`no_mangle` attribute].
|
||||
///
|
||||
/// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #[no_mangle]
|
||||
/// const FOO: i32 = 5;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Constants do not have their symbols exported, and therefore, this
|
||||
/// probably means you meant to use a [`static`], not a [`const`].
|
||||
///
|
||||
/// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
|
||||
/// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
|
||||
NO_MANGLE_CONST_ITEMS,
|
||||
Deny,
|
||||
"const items will not have their symbols exported"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `no_mangle_generic_items` lint detects generic items that must be
|
||||
/// mangled.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #[no_mangle]
|
||||
/// fn foo<T>(t: T) {
|
||||
///
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// An function with generics must have its symbol mangled to accommodate
|
||||
/// the generic parameter. The [`no_mangle` attribute] has no effect in
|
||||
/// this situation, and should be removed.
|
||||
///
|
||||
/// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
|
||||
NO_MANGLE_GENERIC_ITEMS,
|
||||
Warn,
|
||||
"generic items must be mangled"
|
||||
@ -882,6 +1120,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
|
||||
/// T` because it is [undefined behavior].
|
||||
///
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// unsafe {
|
||||
/// let y = std::mem::transmute::<&i32, &mut i32>(&5);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Certain assumptions are made about aliasing of data, and this transmute
|
||||
/// violates those assumptions. Consider using [`UnsafeCell`] instead.
|
||||
///
|
||||
/// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
|
||||
MUTABLE_TRANSMUTES,
|
||||
Deny,
|
||||
"mutating transmuted &mut T from &T may cause undefined behavior"
|
||||
@ -931,6 +1190,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unstable_features` is deprecated and should no longer be used.
|
||||
UNSTABLE_FEATURES,
|
||||
Allow,
|
||||
"enabling unstable features (deprecated. do not use)"
|
||||
@ -956,6 +1216,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unreachable_pub` lint triggers for `pub` items not reachable from
|
||||
/// the crate root.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unreachable_pub)]
|
||||
/// mod foo {
|
||||
/// pub mod bar {
|
||||
///
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// A bare `pub` visibility may be misleading if the item is not actually
|
||||
/// publicly exported from the crate. The `pub(crate)` visibility is
|
||||
/// recommended to be used instead, which more clearly expresses the intent
|
||||
/// that the item is only visible within its own crate.
|
||||
///
|
||||
/// This lint is "allow" by default because it will trigger for a large
|
||||
/// amount existing Rust code, and has some false-positives. Eventually it
|
||||
/// is desired for this to become warn-by-default.
|
||||
pub UNREACHABLE_PUB,
|
||||
Allow,
|
||||
"`pub` items not reachable from crate root"
|
||||
@ -1035,6 +1321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `type_alias_bounds` lint detects bounds in type aliases.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// type SendVec<T: Send> = Vec<T>;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The trait bounds in a type alias are currently ignored, and should not
|
||||
/// be included to avoid confusion. This was previously allowed
|
||||
/// unintentionally; this may become a hard error in the future.
|
||||
TYPE_ALIAS_BOUNDS,
|
||||
Warn,
|
||||
"bounds in type aliases are not enforced"
|
||||
@ -1194,6 +1495,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `trivial_bounds` lint detects trait bounds that don't depend on
|
||||
/// any type parameters.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(trivial_bounds)]
|
||||
/// pub struct A where i32: Copy;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Usually you would not write a trait bound that you know is always
|
||||
/// true, or never true. However, when using macros, the macro may not
|
||||
/// know whether or not the constraint would hold or not at the time when
|
||||
/// generating the code. Currently, the compiler does not alert you if the
|
||||
/// constraint is always true, and generates an error if it is never true.
|
||||
/// The `trivial_bounds` feature changes this to be a warning in both
|
||||
/// cases, giving macros more freedom and flexibility to generate code,
|
||||
/// while still providing a signal when writing non-macro code that
|
||||
/// something is amiss.
|
||||
///
|
||||
/// See [RFC 2056] for more details. This feature is currently only
|
||||
/// available on the nightly channel, see [tracking issue #48214].
|
||||
///
|
||||
/// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
|
||||
/// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
|
||||
TRIVIAL_BOUNDS,
|
||||
Warn,
|
||||
"these bounds don't depend on an type parameters"
|
||||
@ -1270,6 +1600,29 @@ declare_lint_pass!(
|
||||
);
|
||||
|
||||
declare_lint! {
|
||||
/// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
|
||||
/// pattern], which is deprecated.
|
||||
///
|
||||
/// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let x = 123;
|
||||
/// match x {
|
||||
/// 0...100 => {}
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The `...` range pattern syntax was changed to `..=` to avoid potential
|
||||
/// confusion with the [`..` range expression]. Use the new form instead.
|
||||
///
|
||||
/// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
|
||||
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
|
||||
Warn,
|
||||
"`...` range patterns are deprecated"
|
||||
@ -1356,6 +1709,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unnameable_test_items` lint detects [`#[test]`][test] functions
|
||||
/// that are not able to be run by the test harness because they are in a
|
||||
/// position where they are not nameable.
|
||||
///
|
||||
/// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,test
|
||||
/// fn main() {
|
||||
/// #[test]
|
||||
/// fn foo() {
|
||||
/// // This test will not fail because it does not run.
|
||||
/// assert_eq!(1, 2);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In order for the test harness to run a test, the test function must be
|
||||
/// located in a position where it can be accessed from the crate root.
|
||||
/// This generally means it must be defined in a module, and not anywhere
|
||||
/// else such as inside another function. The compiler previously allowed
|
||||
/// this without an error, so a lint was added as an alert that a test is
|
||||
/// not being used. Whether or not this should be allowed has not yet been
|
||||
/// decided, see [RFC 2471] and [issue #36629].
|
||||
///
|
||||
/// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
|
||||
/// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
|
||||
UNNAMEABLE_TEST_ITEMS,
|
||||
Warn,
|
||||
"detects an item that cannot be named being marked as `#[test_case]`",
|
||||
@ -1401,6 +1786,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `keyword_idents` lint detects edition keywords being used as an
|
||||
/// identifier.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2015,compile_fail
|
||||
/// #![deny(keyword_idents)]
|
||||
/// // edition 2015
|
||||
/// fn dyn() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Rust [editions] allow the language to evolve without breaking
|
||||
/// backwards compatibility. This lint catches code that uses new keywords
|
||||
/// that are added to the language that are used as identifiers (such as a
|
||||
/// variable name, function name, etc.). If you switch the compiler to a
|
||||
/// new edition without updating the code, then it will fail to compile if
|
||||
/// you are using a new keyword as an identifier.
|
||||
///
|
||||
/// You can manually change the identifiers to a non-keyword, or use a
|
||||
/// [raw identifier], for example `r#dyn`, to transition to a new edition.
|
||||
///
|
||||
/// This lint solves the problem automatically. It is "allow" by default
|
||||
/// because the code is perfectly valid in older editions. The [`cargo
|
||||
/// fix`] tool with the `--edition` flag will switch this lint to "warn"
|
||||
/// and automatically apply the suggested fix from the compiler (which is
|
||||
/// to use a raw identifier). This provides a completely automated way to
|
||||
/// update old code for a new edition.
|
||||
///
|
||||
/// [editions]: https://doc.rust-lang.org/edition-guide/
|
||||
/// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
|
||||
/// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
|
||||
pub KEYWORD_IDENTS,
|
||||
Allow,
|
||||
"detects edition keywords being used as an identifier",
|
||||
@ -1802,6 +2222,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `incomplete_features` lint detects unstable features enabled with
|
||||
/// the [`feature` attribute] that may function improperly in some or all
|
||||
/// cases.
|
||||
///
|
||||
/// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(generic_associated_types)]
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Although it is encouraged for people to experiment with unstable
|
||||
/// features, some of them are known to be incomplete or faulty. This lint
|
||||
/// is a signal that the feature has not yet been finished, and you may
|
||||
/// experience problems with it.
|
||||
pub INCOMPLETE_FEATURES,
|
||||
Warn,
|
||||
"incomplete features that may function improperly in some or all cases"
|
||||
@ -1842,6 +2282,36 @@ impl EarlyLintPass for IncompleteFeatures {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `invalid_value` lint detects creating a value that is not valid,
|
||||
/// such as a NULL reference.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # #![allow(unused)]
|
||||
/// unsafe {
|
||||
/// let x: &'static i32 = std::mem::zeroed();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In some situations the compiler can detect that the code is creating
|
||||
/// an invalid value, which should be avoided.
|
||||
///
|
||||
/// In particular, this lint will check for improper use of
|
||||
/// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
|
||||
/// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
|
||||
/// lint should provide extra information to indicate what the problem is
|
||||
/// and a possible solution.
|
||||
///
|
||||
/// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
|
||||
/// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
|
||||
/// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
/// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
pub INVALID_VALUE,
|
||||
Warn,
|
||||
"an invalid value is being created (such as a NULL reference)"
|
||||
@ -2073,6 +2543,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `clashing_extern_declarations` lint detects when an `extern fn`
|
||||
/// has been declared with the same name but different types.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// mod m {
|
||||
/// extern "C" {
|
||||
/// fn foo();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn foo(_: u32);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Because two symbols of the same name cannot be resolved to two
|
||||
/// different functions at link time, and one function cannot possibly
|
||||
/// have two types, a clashing extern declaration is almost certainly a
|
||||
/// mistake. Check to make sure that the `extern` definitions are correct
|
||||
/// and equivalent, and possibly consider unifying them in one location.
|
||||
///
|
||||
/// This lint does not run between crates because a project may have
|
||||
/// dependencies which both rely on the same extern function, but declare
|
||||
/// it in a different (but valid) way. For example, they may both declare
|
||||
/// an opaque type for one or more of the arguments (which would end up
|
||||
/// distinct types), or use types that are valid conversions in the
|
||||
/// language the `extern fn` is defined in. In these cases, the compiler
|
||||
/// can't say that the clashing declaration is incorrect.
|
||||
pub CLASHING_EXTERN_DECLARATIONS,
|
||||
Warn,
|
||||
"detects when an extern fn has been declared with the same name but different types"
|
||||
|
@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_ascii_idents` lint detects non-ASCII identifiers.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![allow(unused)]
|
||||
/// #![feature(non_ascii_idents)]
|
||||
/// #![deny(non_ascii_idents)]
|
||||
/// fn main() {
|
||||
/// let föö = 1;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Currently on stable Rust, identifiers must contain ASCII characters.
|
||||
/// The [`non_ascii_idents`] nightly-only feature allows identifiers to
|
||||
/// contain non-ASCII characters. This lint allows projects that wish to
|
||||
/// retain the limit of only using ASCII characters to switch this lint to
|
||||
/// "forbid" (for example to ease collaboration or for security reasons).
|
||||
/// See [RFC 2457] for more details.
|
||||
///
|
||||
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
|
||||
/// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md
|
||||
pub NON_ASCII_IDENTS,
|
||||
Allow,
|
||||
"detects non-ASCII identifiers",
|
||||
@ -11,6 +37,37 @@ declare_lint! {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in
|
||||
/// identifiers.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// #![feature(non_ascii_idents)]
|
||||
/// const µ: f64 = 0.000001;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// With the [`non_ascii_idents`] nightly-only feature enabled,
|
||||
/// identifiers are allowed to use non-ASCII characters. This lint warns
|
||||
/// about using characters which are not commonly used, and may cause
|
||||
/// visual confusion.
|
||||
///
|
||||
/// This lint is triggered by identifiers that contain a codepoint that is
|
||||
/// not part of the set of "Allowed" codepoints as described by [Unicode®
|
||||
/// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General
|
||||
/// Security Profile for Identifiers][TR39Allowed].
|
||||
///
|
||||
/// Note that the set of uncommon codepoints may change over time. Beware
|
||||
/// that if you "forbid" this lint that existing code may fail in the
|
||||
/// future.
|
||||
///
|
||||
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
|
||||
/// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile
|
||||
pub UNCOMMON_CODEPOINTS,
|
||||
Warn,
|
||||
"detects uncommon Unicode codepoints in identifiers",
|
||||
@ -18,6 +75,43 @@ declare_lint! {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `confusable_idents` lint detects visually confusable pairs between
|
||||
/// identifiers.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(non_ascii_idents)]
|
||||
///
|
||||
/// // Latin Capital Letter E With Caron
|
||||
/// pub const Ě: i32 = 1;
|
||||
/// // Latin Capital Letter E With Breve
|
||||
/// pub const Ĕ: i32 = 2;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// With the [`non_ascii_idents`] nightly-only feature enabled,
|
||||
/// identifiers are allowed to use non-ASCII characters. This lint warns
|
||||
/// when different identifiers may appear visually similar, which can
|
||||
/// cause confusion.
|
||||
///
|
||||
/// The confusable detection algorithm is based on [Unicode® Technical
|
||||
/// Standard #39 Unicode Security Mechanisms Section 4 Confusable
|
||||
/// Detection][TR39Confusable]. For every distinct identifier X execute
|
||||
/// the function `skeleton(X)`. If there exist two distinct identifiers X
|
||||
/// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it.
|
||||
/// The compiler uses the same mechanism to check if an identifier is too
|
||||
/// similar to a keyword.
|
||||
///
|
||||
/// Note that the set of confusable characters may change over time.
|
||||
/// Beware that if you "forbid" this lint that existing code may fail in
|
||||
/// the future.
|
||||
///
|
||||
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
|
||||
/// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection
|
||||
pub CONFUSABLE_IDENTS,
|
||||
Warn,
|
||||
"detects visually confusable pairs between identifiers",
|
||||
@ -25,6 +119,41 @@ declare_lint! {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `mixed_script_confusables` lint detects visually confusable
|
||||
/// characters in identifiers between different [scripts].
|
||||
///
|
||||
/// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode)
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(non_ascii_idents)]
|
||||
///
|
||||
/// // The Japanese katakana character エ can be confused with the Han character 工.
|
||||
/// const エ: &'static str = "アイウ";
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// With the [`non_ascii_idents`] nightly-only feature enabled,
|
||||
/// identifiers are allowed to use non-ASCII characters. This lint warns
|
||||
/// when characters between different scripts may appear visually similar,
|
||||
/// which can cause confusion.
|
||||
///
|
||||
/// If the crate contains other identifiers in the same script that have
|
||||
/// non-confusable characters, then this lint will *not* be issued. For
|
||||
/// example, if the example given above has another identifier with
|
||||
/// katakana characters (such as `let カタカナ = 123;`), then this indicates
|
||||
/// that you are intentionally using katakana, and it will not warn about
|
||||
/// it.
|
||||
///
|
||||
/// Note that the set of confusable characters may change over time.
|
||||
/// Beware that if you "forbid" this lint that existing code may fail in
|
||||
/// the future.
|
||||
///
|
||||
/// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
|
||||
pub MIXED_SCRIPT_CONFUSABLES,
|
||||
Warn,
|
||||
"detects Unicode scripts whose mixed script confusables codepoints are solely used",
|
||||
|
@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_camel_case_types` lint detects types, variants, traits and
|
||||
/// type parameters that don't have camel case names.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// struct my_struct;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The preferred style for these identifiers is to use "camel case", such
|
||||
/// as `MyStruct`, where the first letter should not be lowercase, and
|
||||
/// should not use underscores between letters. Underscores are allowed at
|
||||
/// the beginning and end of the identifier, as well as between
|
||||
/// non-letters (such as `X86_64`).
|
||||
pub NON_CAMEL_CASE_TYPES,
|
||||
Warn,
|
||||
"types, variants, traits and type parameters should have camel case names"
|
||||
@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_snake_case` lint detects variables, methods, functions,
|
||||
/// lifetime parameters and modules that don't have snake case names.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let MY_VALUE = 5;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The preferred style for these identifiers is to use "snake case",
|
||||
/// where all the characters are in lowercase, with words separated with a
|
||||
/// single underscore, such as `my_value`.
|
||||
pub NON_SNAKE_CASE,
|
||||
Warn,
|
||||
"variables, methods, functions, lifetime parameters and modules should have snake case names"
|
||||
@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `non_upper_case_globals` lint detects static items that don't have
|
||||
/// uppercase identifiers.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// static max_points: i32 = 5;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The preferred style is for static item names to use all uppercase
|
||||
/// letters such as `MAX_POINTS`.
|
||||
pub NON_UPPER_CASE_GLOBALS,
|
||||
Warn,
|
||||
"static constants should have uppercase identifiers"
|
||||
|
@ -4,6 +4,21 @@ use rustc_errors::Applicability;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_lint! {
|
||||
/// The `redundant_semicolons` lint detects unnecessary trailing
|
||||
/// semicolons.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let _ = 123;;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Extra semicolons are not needed, and may be removed to avoid confusion
|
||||
/// and visual clutter.
|
||||
pub REDUNDANT_SEMICOLONS,
|
||||
Warn,
|
||||
"detects unnecessary trailing semicolons"
|
||||
|
@ -23,18 +23,82 @@ use std::cmp;
|
||||
use tracing::debug;
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_comparisons` lint detects comparisons made useless by
|
||||
/// limits of the types involved.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// fn foo(x: u8) {
|
||||
/// x >= 0;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// A useless comparison may indicate a mistake, and should be fixed or
|
||||
/// removed.
|
||||
UNUSED_COMPARISONS,
|
||||
Warn,
|
||||
"comparisons made useless by limits of the types involved"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `overflowing_literals` lint detects literal out of range for its
|
||||
/// type.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// let x: u8 = 1000;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// It is usually a mistake to use a literal that overflows the type where
|
||||
/// it is used. Either use a literal that is within range, or change the
|
||||
/// type to be within the range of the literal.
|
||||
OVERFLOWING_LITERALS,
|
||||
Deny,
|
||||
"literal out of range for its type"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `variant_size_differences` lint detects enums with widely varying
|
||||
/// variant sizes.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(variant_size_differences)]
|
||||
/// enum En {
|
||||
/// V0(u8),
|
||||
/// VBig([u8; 1024]),
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// It can be a mistake to add a variant to an enum that is much larger
|
||||
/// than the other variants, bloating the overall size required for all
|
||||
/// variants. This can impact performance and memory usage. This is
|
||||
/// triggered if one variant is more than 3 times larger than the
|
||||
/// second-largest variant.
|
||||
///
|
||||
/// Consider placing the large variant's contents on the heap (for example
|
||||
/// via [`Box`]) to keep the overall size of the enum itself down.
|
||||
///
|
||||
/// This lint is "allow" by default because it can be noisy, and may not be
|
||||
/// an actual problem. Decisions about this should be guided with
|
||||
/// profiling and benchmarking.
|
||||
///
|
||||
/// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
Allow,
|
||||
"detects enums with widely varying variant sizes"
|
||||
@ -495,6 +559,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `improper_ctypes` lint detects incorrect use of types in foreign
|
||||
/// modules.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// extern "C" {
|
||||
/// static STATIC: String;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The compiler has several checks to verify that types used in `extern`
|
||||
/// blocks are safe and follow certain rules to ensure proper
|
||||
/// compatibility with the foreign interfaces. This lint is issued when it
|
||||
/// detects a probable mistake in a definition. The lint usually should
|
||||
/// provide a description of the issue, along with possibly a hint on how
|
||||
/// to resolve it.
|
||||
IMPROPER_CTYPES,
|
||||
Warn,
|
||||
"proper use of libc types in foreign modules"
|
||||
@ -503,6 +588,27 @@ declare_lint! {
|
||||
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
|
||||
|
||||
declare_lint! {
|
||||
/// The `improper_ctypes_definitions` lint detects incorrect use of
|
||||
/// [`extern` function] definitions.
|
||||
///
|
||||
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// pub extern "C" fn str_type(p: &str) { }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// There are many parameter and return types that may be specified in an
|
||||
/// `extern` function that are not compatible with the given ABI. This
|
||||
/// lint is an alert that these types should not be used. The lint usually
|
||||
/// should provide a description of the issue, along with possibly a hint
|
||||
/// on how to resolve it.
|
||||
IMPROPER_CTYPES_DEFINITIONS,
|
||||
Warn,
|
||||
"proper use of libc types in foreign item definitions"
|
||||
|
@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
use tracing::debug;
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_must_use` lint detects unused result of a type flagged as
|
||||
/// `#[must_use]`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// fn returns_result() -> Result<(), ()> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// returns_result();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The `#[must_use]` attribute is an indicator that it is a mistake to
|
||||
/// ignore the value. See [the reference] for more details.
|
||||
///
|
||||
/// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
||||
pub UNUSED_MUST_USE,
|
||||
Warn,
|
||||
"unused result of a type flagged as `#[must_use]`",
|
||||
@ -27,6 +50,39 @@ declare_lint! {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_results` lint checks for the unused result of an
|
||||
/// expression in a statement.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unused_results)]
|
||||
/// fn foo<T>() -> T { panic!() }
|
||||
///
|
||||
/// fn main() {
|
||||
/// foo::<usize>();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Ignoring the return value of a function may indicate a mistake. In
|
||||
/// cases were it is almost certain that the result should be used, it is
|
||||
/// recommended to annotate the function with the [`must_use` attribute].
|
||||
/// Failure to use such a return value will trigger the [`unused_must_use`
|
||||
/// lint] which is warn-by-default. The `unused_results` lint is
|
||||
/// essentially the same, but triggers for *all* return values.
|
||||
///
|
||||
/// This lint is "allow" by default because it can be noisy, and may not be
|
||||
/// an actual problem. For example, calling the `remove` method of a `Vec`
|
||||
/// or `HashMap` returns the previous value, which you may not care about.
|
||||
/// Using this lint would require explicitly ignoring or discarding such
|
||||
/// values.
|
||||
///
|
||||
/// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
||||
/// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
|
||||
pub UNUSED_RESULTS,
|
||||
Allow,
|
||||
"unused result of an expression in a statement"
|
||||
@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `path_statements` lint detects path statements with no effect.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let x = 42;
|
||||
///
|
||||
/// x;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// It is usually a mistake to have a statement that has no effect.
|
||||
pub PATH_STATEMENTS,
|
||||
Warn,
|
||||
"path statements with no effect"
|
||||
@ -635,6 +706,21 @@ trait UnusedDelimLint {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_parens` lint detects `if`, `match`, `while` and `return`
|
||||
/// with parentheses; they do not need them.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// if(true) {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The parenthesis are not needed, and should be removed. This is the
|
||||
/// preferred style for writing these expressions.
|
||||
pub(super) UNUSED_PARENS,
|
||||
Warn,
|
||||
"`if`, `match`, `while` and `return` do not need parentheses"
|
||||
@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_braces` lint detects unnecessary braces around an
|
||||
/// expression.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// if { true } {
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// The braces are not needed, and should be removed. This is the
|
||||
/// preferred style for writing these expressions.
|
||||
pub(super) UNUSED_BRACES,
|
||||
Warn,
|
||||
"unnecessary braces around an expression"
|
||||
@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_import_braces` lint catches unnecessary braces around an
|
||||
/// imported item.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unused_import_braces)]
|
||||
/// use test::{A};
|
||||
///
|
||||
/// pub mod test {
|
||||
/// pub struct A;
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// If there is only a single item, then remove the braces (`use test::A;`
|
||||
/// for example).
|
||||
///
|
||||
/// This lint is "allow" by default because it is only enforcing a
|
||||
/// stylistic choice.
|
||||
UNUSED_IMPORT_BRACES,
|
||||
Allow,
|
||||
"unnecessary braces around an imported item"
|
||||
@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unused_allocation` lint detects unnecessary allocations that can
|
||||
/// be eliminated.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(box_syntax)]
|
||||
/// fn main() {
|
||||
/// let a = (box [1,2,3]).len();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// When a `box` expression is immediately coerced to a reference, then
|
||||
/// the allocation is unnecessary, and a reference (using `&` or `&mut`)
|
||||
/// should be used instead to avoid the allocation.
|
||||
pub(super) UNUSED_ALLOCATION,
|
||||
Warn,
|
||||
"detects unnecessary allocations that can be eliminated"
|
||||
|
@ -65,9 +65,15 @@ pub struct Lint {
|
||||
///
|
||||
/// The name is written with underscores, e.g., "unused_imports".
|
||||
/// On the command line, underscores become dashes.
|
||||
///
|
||||
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
|
||||
/// for naming guidelines.
|
||||
pub name: &'static str,
|
||||
|
||||
/// Default level for the lint.
|
||||
///
|
||||
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
|
||||
/// for guidelines on choosing a default level.
|
||||
pub default_level: Level,
|
||||
|
||||
/// Description of the lint or the issue it detects.
|
||||
@ -275,17 +281,60 @@ impl LintBuffer {
|
||||
}
|
||||
|
||||
/// Declares a static item of type `&'static Lint`.
|
||||
///
|
||||
/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
|
||||
/// and guidelines on writing lints.
|
||||
///
|
||||
/// The macro call should start with a doc comment explaining the lint
|
||||
/// which will be embedded in the rustc user documentation book. It should
|
||||
/// be written in markdown and have a format that looks like this:
|
||||
///
|
||||
/// ```rust,ignore (doc-example)
|
||||
/// /// The `my_lint_name` lint detects [short explanation here].
|
||||
/// ///
|
||||
/// /// ### Example
|
||||
/// ///
|
||||
/// /// ```rust
|
||||
/// /// [insert a concise example that triggers the lint]
|
||||
/// /// ```
|
||||
/// ///
|
||||
/// /// {{produces}}
|
||||
/// ///
|
||||
/// /// ### Explanation
|
||||
/// ///
|
||||
/// /// This should be a detailed explanation of *why* the lint exists,
|
||||
/// /// and also include suggestions on how the user should fix the problem.
|
||||
/// /// Try to keep the text simple enough that a beginner can understand,
|
||||
/// /// and include links to other documentation for terminology that a
|
||||
/// /// beginner may not be familiar with. If this is "allow" by default,
|
||||
/// /// it should explain why (are there false positives or other issues?). If
|
||||
/// /// this is a future-incompatible lint, it should say so, with text that
|
||||
/// /// looks roughly like this:
|
||||
/// ///
|
||||
/// /// This is a [future-incompatible] lint to transition this to a hard
|
||||
/// /// error in the future. See [issue #xxxxx] for more details.
|
||||
/// ///
|
||||
/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
|
||||
/// ```
|
||||
///
|
||||
/// The `{{produces}}` tag will be automatically replaced with the output from
|
||||
/// the example by the build system. You can build and view the rustc book
|
||||
/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
|
||||
/// complex to run as a simple example (for example, it needs an extern
|
||||
/// crate), mark it with `ignore` and manually paste the expected output below
|
||||
/// the example.
|
||||
#[macro_export]
|
||||
macro_rules! declare_lint {
|
||||
($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
|
||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
|
||||
$crate::declare_lint!(
|
||||
$vis $NAME, $Level, $desc,
|
||||
$(#[$attr])* $vis $NAME, $Level, $desc,
|
||||
);
|
||||
);
|
||||
($vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||
$(@future_incompatible = $fi:expr;)?
|
||||
$(@feature_gate = $gate:expr;)?
|
||||
$($v:ident),*) => (
|
||||
$(#[$attr])*
|
||||
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
|
||||
name: stringify!($NAME),
|
||||
default_level: $crate::lint::$Level,
|
||||
@ -298,9 +347,10 @@ macro_rules! declare_lint {
|
||||
..$crate::lint::Lint::default_fields_for_macro()
|
||||
};
|
||||
);
|
||||
($vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
|
||||
$lint_edition: expr => $edition_level: ident
|
||||
) => (
|
||||
$(#[$attr])*
|
||||
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
|
||||
name: stringify!($NAME),
|
||||
default_level: $crate::lint::$Level,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -66,7 +66,6 @@ book!(
|
||||
Nomicon, "src/doc/nomicon", "nomicon";
|
||||
Reference, "src/doc/reference", "reference";
|
||||
RustByExample, "src/doc/rust-by-example", "rust-by-example";
|
||||
RustcBook, "src/doc/rustc", "rustc";
|
||||
RustdocBook, "src/doc/rustdoc", "rustdoc";
|
||||
);
|
||||
|
||||
@ -718,3 +717,66 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
|
||||
|
||||
symlink_dir(config, src, dst)
|
||||
}
|
||||
|
||||
#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct RustcBook {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for RustcBook {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
let builder = run.builder;
|
||||
run.path("src/doc/rustc").default_condition(builder.config.docs)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(RustcBook {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
/// Builds the rustc book.
|
||||
///
|
||||
/// The lints are auto-generated by a tool, and then merged into the book
|
||||
/// in the "md-doc" directory in the build output directory. Then
|
||||
/// "rustbook" is used to convert it to HTML.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let out_base = builder.md_doc_out(self.target).join("rustc");
|
||||
t!(fs::create_dir_all(&out_base));
|
||||
let out_listing = out_base.join("src/lints");
|
||||
builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
|
||||
builder.info(&format!("Generating lint docs ({})", self.target));
|
||||
let rustc = builder.rustc(self.compiler);
|
||||
// The tool runs `rustc` for extracting output examples, so it needs a
|
||||
// functional sysroot.
|
||||
builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
|
||||
let mut cmd = builder.tool_cmd(Tool::LintDocs);
|
||||
cmd.arg("--src");
|
||||
cmd.arg(builder.src.join("compiler"));
|
||||
cmd.arg("--out");
|
||||
cmd.arg(&out_listing);
|
||||
cmd.arg("--rustc");
|
||||
cmd.arg(rustc);
|
||||
if builder.config.verbose() {
|
||||
cmd.arg("--verbose");
|
||||
}
|
||||
builder.run(&mut cmd);
|
||||
// Run rustbook/mdbook to generate the HTML pages.
|
||||
builder.ensure(RustbookSrc {
|
||||
target: self.target,
|
||||
name: INTERNER.intern_str("rustc"),
|
||||
src: INTERNER.intern_path(out_base),
|
||||
});
|
||||
if is_explicit_request(builder, "src/doc/rustc") {
|
||||
let out = builder.doc_out(self.target);
|
||||
let index = out.join("rustc").join("index.html");
|
||||
open(builder, &index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,6 +367,7 @@ bootstrap_tool!(
|
||||
RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
|
||||
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
|
||||
ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
|
||||
LintDocs, "src/tools/lint-docs", "lint-docs";
|
||||
);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
|
||||
|
@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals
|
||||
|
||||
Here's a list of each lint group, and the lints that they are made up of:
|
||||
|
||||
| group | description | lints |
|
||||
|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals |
|
||||
| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings |
|
||||
| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer |
|
||||
| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub |
|
||||
| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens |
|
||||
| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
|
||||
{{groups-table}}
|
||||
|
||||
Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.
|
||||
|
||||
|
@ -26,3 +26,35 @@ warning: unused variable: `x`
|
||||
This is the `unused_variables` lint, and it tells you that you've introduced
|
||||
a variable that you don't use in your code. That's not *wrong*, so it's not
|
||||
an error, but it might be a bug, so you get a warning.
|
||||
|
||||
## Future-incompatible lints
|
||||
|
||||
Sometimes the compiler needs to be changed to fix an issue that can cause
|
||||
existing code to stop compiling. "Future-incompatible" lints are issued in
|
||||
these cases to give users of Rust a smooth transition to the new behavior.
|
||||
Initially, the compiler will continue to accept the problematic code and issue
|
||||
a warning. The warning has a description of the problem, a notice that this
|
||||
will become an error in the future, and a link to a tracking issue that
|
||||
provides detailed information and an opportunity for feedback. This gives
|
||||
users some time to fix the code to accommodate the change. After some time,
|
||||
the warning may become an error.
|
||||
|
||||
The following is an example of what a future-incompatible looks like:
|
||||
|
||||
```text
|
||||
warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
|
||||
--> lint_example.rs:11:13
|
||||
|
|
||||
11 | let y = &x.data.0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(safe_packed_borrows)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
|
||||
= note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
|
||||
```
|
||||
|
||||
For more information about the process and policy of future-incompatible
|
||||
changes, see [RFC 1589].
|
||||
|
||||
[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md
|
||||
|
@ -1,454 +1,3 @@
|
||||
# Allowed-by-default lints
|
||||
|
||||
These lints are all set to the 'allow' level by default. As such, they won't show up
|
||||
unless you set them to a higher lint level with a flag or attribute.
|
||||
|
||||
## anonymous-parameters
|
||||
|
||||
This lint detects anonymous parameters. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
trait Foo {
|
||||
fn foo(usize);
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: use of deprecated anonymous parameter
|
||||
--> src/lib.rs:5:11
|
||||
|
|
||||
5 | fn foo(usize);
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
|
||||
```
|
||||
|
||||
This syntax is mostly a historical accident, and can be worked around quite
|
||||
easily:
|
||||
|
||||
```rust
|
||||
trait Foo {
|
||||
fn foo(_: usize);
|
||||
}
|
||||
```
|
||||
|
||||
## bare-trait-object
|
||||
|
||||
This lint suggests using `dyn Trait` for trait objects. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
#![feature(dyn_trait)]
|
||||
|
||||
trait Trait { }
|
||||
|
||||
fn takes_trait_object(_: Box<Trait>) {
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: trait objects without an explicit `dyn` are deprecated
|
||||
--> src/lib.rs:7:30
|
||||
|
|
||||
7 | fn takes_trait_object(_: Box<Trait>) {
|
||||
| ^^^^^ help: use `dyn`: `dyn Trait`
|
||||
|
|
||||
```
|
||||
|
||||
To fix it, do as the help message suggests:
|
||||
|
||||
```rust
|
||||
#![feature(dyn_trait)]
|
||||
#![deny(bare_trait_objects)]
|
||||
|
||||
trait Trait { }
|
||||
|
||||
fn takes_trait_object(_: Box<dyn Trait>) {
|
||||
}
|
||||
```
|
||||
|
||||
## box-pointers
|
||||
|
||||
This lints use of the Box type. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
struct Foo {
|
||||
x: Box<isize>,
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: type uses owned (Box type) pointers: std::boxed::Box<isize>
|
||||
--> src/lib.rs:6:5
|
||||
|
|
||||
6 | x: Box<isize> //~ ERROR type uses owned
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
This lint is mostly historical, and not particularly useful. `Box<T>` used to
|
||||
be built into the language, and the only way to do heap allocation. Today's
|
||||
Rust can call into other allocators, etc.
|
||||
|
||||
## elided-lifetime-in-path
|
||||
|
||||
This lint detects the use of hidden lifetime parameters. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
struct Foo<'a> {
|
||||
x: &'a u32
|
||||
}
|
||||
|
||||
fn foo(x: &Foo) {
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: hidden lifetime parameters are deprecated, try `Foo<'_>`
|
||||
--> src/lib.rs:5:12
|
||||
|
|
||||
5 | fn foo(x: &Foo) {
|
||||
| ^^^
|
||||
|
|
||||
```
|
||||
|
||||
Lifetime elision elides this lifetime, but that is being deprecated.
|
||||
|
||||
## missing-copy-implementations
|
||||
|
||||
This lint detects potentially-forgotten implementations of `Copy`. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
pub struct Foo {
|
||||
pub field: i32
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: type could implement `Copy`; consider adding `impl Copy`
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy`
|
||||
4 | | pub field: i32
|
||||
5 | | }
|
||||
| |_^
|
||||
|
|
||||
```
|
||||
|
||||
You can fix the lint by deriving `Copy`.
|
||||
|
||||
This lint is set to 'allow' because this code isn't bad; it's common to write
|
||||
newtypes like this specifically so that a `Copy` type is no longer `Copy`.
|
||||
|
||||
## missing-debug-implementations
|
||||
|
||||
This lint detects missing implementations of `fmt::Debug`. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
pub struct Foo;
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
You can fix the lint by deriving `Debug`.
|
||||
|
||||
## missing-docs
|
||||
|
||||
This lint detects missing documentation for public items. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
pub fn foo() {}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: missing documentation for crate
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | / #![deny(missing_docs)]
|
||||
2 | |
|
||||
3 | | pub fn foo() {}
|
||||
4 | |
|
||||
5 | | fn main() {}
|
||||
| |____________^
|
||||
|
|
||||
|
||||
error: missing documentation for a function
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | pub fn foo() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
```
|
||||
|
||||
To fix the lint, add documentation to all items.
|
||||
|
||||
## single-use-lifetimes
|
||||
|
||||
This lint detects lifetimes that are only used once. Some example code that
|
||||
triggers this lint:
|
||||
|
||||
```rust
|
||||
struct Foo<'x> {
|
||||
x: &'x u32
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: lifetime name `'x` only used once
|
||||
--> src/main.rs:3:12
|
||||
|
|
||||
3 | struct Foo<'x> {
|
||||
| ^^
|
||||
|
|
||||
```
|
||||
|
||||
## trivial-casts
|
||||
|
||||
This lint detects trivial casts which could be replaced with coercion, which may require
|
||||
type ascription or a temporary variable. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
let x: &u32 = &42;
|
||||
let _ = x as *const u32;
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
|
||||
--> src/main.rs:5:13
|
||||
|
|
||||
5 | let _ = x as *const u32;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> src/main.rs:1:9
|
||||
|
|
||||
1 | #![deny(trivial_casts)]
|
||||
| ^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
## trivial-numeric-casts
|
||||
|
||||
This lint detects trivial casts of numeric types which could be removed. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let x = 42i32 as i32;
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
|
||||
--> src/main.rs:4:13
|
||||
|
|
||||
4 | let x = 42i32 as i32;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unreachable-pub
|
||||
|
||||
This lint triggers for `pub` items not reachable from the crate root. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
mod foo {
|
||||
pub mod bar {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: unreachable `pub` item
|
||||
--> src/main.rs:4:5
|
||||
|
|
||||
4 | pub mod bar {
|
||||
| ---^^^^^^^^
|
||||
| |
|
||||
| help: consider restricting its visibility: `pub(crate)`
|
||||
|
|
||||
```
|
||||
|
||||
## unsafe-code
|
||||
|
||||
This lint catches usage of `unsafe` code. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: usage of an `unsafe` block
|
||||
--> src/main.rs:4:5
|
||||
|
|
||||
4 | / unsafe {
|
||||
5 | |
|
||||
6 | | }
|
||||
| |_____^
|
||||
|
|
||||
```
|
||||
|
||||
## unstable-features
|
||||
|
||||
This lint is deprecated and no longer used.
|
||||
|
||||
## unused-extern-crates
|
||||
|
||||
This lint guards against `extern crate` items that are never used. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
extern crate semver;
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: unused extern crate
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | extern crate semver;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-import-braces
|
||||
|
||||
This lint catches unnecessary braces around an imported item. Some example
|
||||
code that triggers this lint:
|
||||
|
||||
```rust
|
||||
use test::{A};
|
||||
|
||||
pub mod test {
|
||||
pub struct A;
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: braces around A is unnecessary
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | use test::{A};
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
To fix it, `use test::A;`
|
||||
|
||||
## unused-qualifications
|
||||
|
||||
This lint detects unnecessarily qualified names. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
mod foo {
|
||||
pub fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use foo::bar;
|
||||
foo::bar();
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: unnecessary qualification
|
||||
--> src/main.rs:9:5
|
||||
|
|
||||
9 | foo::bar();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
You can call `bar()` directly, without the `foo::`.
|
||||
|
||||
## unused-results
|
||||
|
||||
This lint checks for the unused result of an expression in a statement. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,no_run
|
||||
fn foo<T>() -> T { panic!() }
|
||||
|
||||
fn main() {
|
||||
foo::<usize>();
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: unused result
|
||||
--> src/main.rs:6:5
|
||||
|
|
||||
6 | foo::<usize>();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## variant-size-differences
|
||||
|
||||
This lint detects enums with widely varying variant sizes. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
enum En {
|
||||
V0(u8),
|
||||
VBig([u8; 1024]),
|
||||
}
|
||||
```
|
||||
|
||||
When set to 'deny', this will produce:
|
||||
|
||||
```text
|
||||
error: enum variant is more than three times larger (1024 bytes) than the next largest
|
||||
--> src/main.rs:5:5
|
||||
|
|
||||
5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
This file is auto-generated by the lint-docs script.
|
||||
|
@ -1,203 +1,3 @@
|
||||
# Deny-by-default lints
|
||||
|
||||
These lints are all set to the 'deny' level by default.
|
||||
|
||||
## exceeding-bitshifts
|
||||
|
||||
This lint detects that a shift exceeds the type's number of bits. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
1_i32 << 32;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: bitshift exceeds the type's number of bits
|
||||
--> src/main.rs:2:5
|
||||
|
|
||||
2 | 1_i32 << 32;
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## invalid-type-param-default
|
||||
|
||||
This lint detects type parameter default erroneously allowed in invalid location. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
fn foo<T=i32>(t: T) {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
|
||||
--> src/main.rs:4:8
|
||||
|
|
||||
4 | fn foo<T=i32>(t: T) {}
|
||||
| ^
|
||||
|
|
||||
= note: `#[deny(invalid_type_param_default)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
|
||||
```
|
||||
|
||||
## mutable-transmutes
|
||||
|
||||
This lint catches transmuting from `&T` to `&mut T` because it is undefined
|
||||
behavior. Some example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
unsafe {
|
||||
let y = std::mem::transmute::<&i32, &mut i32>(&5);
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
|
||||
--> src/main.rs:3:17
|
||||
|
|
||||
3 | let y = std::mem::transmute::<&i32, &mut i32>(&5);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
|
||||
## no-mangle-const-items
|
||||
|
||||
This lint detects any `const` items with the `#[no_mangle]` attribute.
|
||||
Constants do not have their symbols exported, and therefore, this probably
|
||||
means you meant to use a `static`, not a `const`. Some example code that
|
||||
triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
#[no_mangle]
|
||||
const FOO: i32 = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: const items should never be `#[no_mangle]`
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | const FOO: i32 = 5;
|
||||
| -----^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: try a static value: `pub static`
|
||||
|
|
||||
```
|
||||
|
||||
## overflowing-literals
|
||||
|
||||
This lint detects literal out of range for its type. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,compile_fail
|
||||
let x: u8 = 1000;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: literal out of range for u8
|
||||
--> src/main.rs:2:17
|
||||
|
|
||||
2 | let x: u8 = 1000;
|
||||
| ^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## patterns-in-fns-without-body
|
||||
|
||||
This lint detects patterns in functions without body were that were
|
||||
previously erroneously allowed. Some example code that triggers this lint:
|
||||
|
||||
```rust,compile_fail
|
||||
trait Trait {
|
||||
fn foo(mut arg: u8);
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: patterns aren't allowed in methods without bodies
|
||||
--> src/main.rs:2:12
|
||||
|
|
||||
2 | fn foo(mut arg: u8);
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `#[warn(patterns_in_fns_without_body)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
|
||||
```
|
||||
|
||||
To fix this, remove the pattern; it can be used in the implementation without
|
||||
being used in the definition. That is:
|
||||
|
||||
```rust
|
||||
trait Trait {
|
||||
fn foo(arg: u8);
|
||||
}
|
||||
|
||||
impl Trait for i32 {
|
||||
fn foo(mut arg: u8) {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## pub-use-of-private-extern-crate
|
||||
|
||||
This lint detects a specific situation of re-exporting a private `extern crate`;
|
||||
|
||||
## unknown-crate-types
|
||||
|
||||
This lint detects an unknown crate type found in a `#[crate_type]` directive. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
#![crate_type="lol"]
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: invalid `crate_type` value
|
||||
--> src/lib.rs:1:1
|
||||
|
|
||||
1 | #![crate_type="lol"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## const-err
|
||||
|
||||
This lint detects expressions that will always panic at runtime and would be an
|
||||
error in a `const` context.
|
||||
|
||||
```rust,ignore
|
||||
let _ = [0; 4][4];
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error: index out of bounds: the len is 4 but the index is 4
|
||||
--> src/lib.rs:1:9
|
||||
|
|
||||
1 | let _ = [0; 4][4];
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## order-dependent-trait-objects
|
||||
|
||||
This lint detects a trait coherency violation that would allow creating two
|
||||
trait impls for the same dynamic trait object involving marker traits.
|
||||
This file is auto-generated by the lint-docs script.
|
||||
|
@ -1,903 +1,3 @@
|
||||
# Warn-by-default lints
|
||||
|
||||
These lints are all set to the 'warn' level by default.
|
||||
|
||||
## const-err
|
||||
|
||||
This lint detects an erroneous expression while doing constant evaluation. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
let b = 200u8 + 200u8;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: attempt to add with overflow
|
||||
--> src/main.rs:2:9
|
||||
|
|
||||
2 | let b = 200u8 + 200u8;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## dead-code
|
||||
|
||||
This lint detects unused, unexported items. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
fn foo() {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: function is never used: `foo`
|
||||
--> src/lib.rs:2:1
|
||||
|
|
||||
2 | fn foo() {}
|
||||
| ^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## deprecated
|
||||
|
||||
This lint detects use of deprecated items. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[deprecated]
|
||||
fn foo() {}
|
||||
|
||||
fn bar() {
|
||||
foo();
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: use of deprecated item 'foo'
|
||||
--> src/lib.rs:7:5
|
||||
|
|
||||
7 | foo();
|
||||
| ^^^
|
||||
|
|
||||
```
|
||||
|
||||
## illegal-floating-point-literal-pattern
|
||||
|
||||
This lint detects floating-point literals used in patterns. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
let x = 42.0;
|
||||
|
||||
match x {
|
||||
5.0 => {},
|
||||
_ => {},
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: floating-point literals cannot be used in patterns
|
||||
--> src/main.rs:4:9
|
||||
|
|
||||
4 | 5.0 => {},
|
||||
| ^^^
|
||||
|
|
||||
= note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
|
||||
```
|
||||
|
||||
## improper-ctypes
|
||||
|
||||
This lint detects proper use of libc types in foreign modules. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
extern "C" {
|
||||
static STATIC: String;
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type
|
||||
--> src/main.rs:2:20
|
||||
|
|
||||
2 | static STATIC: String;
|
||||
| ^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## late-bound-lifetime-arguments
|
||||
|
||||
This lint detects generic lifetime arguments in path segments with
|
||||
late bound lifetime parameters. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
S.late::<'static>(&0, &0);
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
|
||||
--> src/main.rs:8:14
|
||||
|
|
||||
4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
|
||||
| -- the late bound lifetime parameter is introduced here
|
||||
...
|
||||
8 | S.late::<'static>(&0, &0);
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `#[warn(late_bound_lifetime_arguments)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
|
||||
```
|
||||
|
||||
## non-camel-case-types
|
||||
|
||||
This lint detects types, variants, traits and type parameters that don't have
|
||||
camel case names. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
struct s;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: type `s` should have a camel case name such as `S`
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | struct s;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## non-shorthand-field-patterns
|
||||
|
||||
This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let p = Point {
|
||||
x: 5,
|
||||
y: 5,
|
||||
};
|
||||
|
||||
match p {
|
||||
Point { x: x, y: y } => (),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: the `x:` in this pattern is redundant
|
||||
--> src/main.rs:14:17
|
||||
|
|
||||
14 | Point { x: x, y: y } => (),
|
||||
| --^^
|
||||
| |
|
||||
| help: remove this
|
||||
|
|
||||
|
||||
warning: the `y:` in this pattern is redundant
|
||||
--> src/main.rs:14:23
|
||||
|
|
||||
14 | Point { x: x, y: y } => (),
|
||||
| --^^
|
||||
| |
|
||||
| help: remove this
|
||||
|
||||
```
|
||||
|
||||
## non-snake-case
|
||||
|
||||
This lint detects variables, methods, functions, lifetime parameters and
|
||||
modules that don't have snake case names. Some example code that triggers
|
||||
this lint:
|
||||
|
||||
```rust
|
||||
let X = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: variable `X` should have a snake case name such as `x`
|
||||
--> src/main.rs:2:9
|
||||
|
|
||||
2 | let X = 5;
|
||||
| ^
|
||||
|
|
||||
```
|
||||
|
||||
## non-upper-case-globals
|
||||
|
||||
This lint detects static constants that don't have uppercase identifiers.
|
||||
Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
static x: i32 = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: static variable `x` should have an upper case name such as `X`
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | static x: i32 = 5;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## no-mangle-generic-items
|
||||
|
||||
This lint detects generic items must be mangled. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
fn foo<T>(t: T) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: functions generic over types must be mangled
|
||||
--> src/main.rs:2:1
|
||||
|
|
||||
1 | #[no_mangle]
|
||||
| ------------ help: remove this attribute
|
||||
2 | / fn foo<T>(t: T) {
|
||||
3 | |
|
||||
4 | | }
|
||||
| |_^
|
||||
|
|
||||
```
|
||||
|
||||
## path-statements
|
||||
|
||||
This lint detects path statements with no effect. Some example code that
|
||||
triggers this lint:
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
|
||||
x;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: path statement with no effect
|
||||
--> src/main.rs:3:5
|
||||
|
|
||||
3 | x;
|
||||
| ^^
|
||||
|
|
||||
```
|
||||
|
||||
## private-in-public
|
||||
|
||||
This lint detects private items in public interfaces not caught by the old implementation. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
pub trait Trait {
|
||||
type A;
|
||||
}
|
||||
|
||||
pub struct S;
|
||||
|
||||
mod foo {
|
||||
struct Z;
|
||||
|
||||
impl ::Trait for ::S {
|
||||
type A = Z;
|
||||
}
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
error[E0446]: private type `foo::Z` in public interface
|
||||
--> src/main.rs:11:9
|
||||
|
|
||||
11 | type A = Z;
|
||||
| ^^^^^^^^^^^ can't leak private type
|
||||
```
|
||||
|
||||
## private-no-mangle-fns
|
||||
|
||||
This lint detects functions marked `#[no_mangle]` that are also private.
|
||||
Given that private functions aren't exposed publicly, and `#[no_mangle]`
|
||||
controls the public symbol, this combination is erroneous. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
fn foo() {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: function is marked `#[no_mangle]`, but not exported
|
||||
--> src/main.rs:2:1
|
||||
|
|
||||
2 | fn foo() {}
|
||||
| -^^^^^^^^^^
|
||||
| |
|
||||
| help: try making it public: `pub`
|
||||
|
|
||||
```
|
||||
|
||||
To fix this, either make it public or remove the `#[no_mangle]`.
|
||||
|
||||
## private-no-mangle-statics
|
||||
|
||||
This lint detects any statics marked `#[no_mangle]` that are private.
|
||||
Given that private statics aren't exposed publicly, and `#[no_mangle]`
|
||||
controls the public symbol, this combination is erroneous. Some example code
|
||||
that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
static X: i32 = 4;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: static is marked `#[no_mangle]`, but not exported
|
||||
--> src/main.rs:2:1
|
||||
|
|
||||
2 | static X: i32 = 4;
|
||||
| -^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: try making it public: `pub`
|
||||
|
|
||||
```
|
||||
|
||||
To fix this, either make it public or remove the `#[no_mangle]`.
|
||||
|
||||
## renamed-and-removed-lints
|
||||
|
||||
This lint detects lints that have been renamed or removed. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#![deny(raw_pointer_derive)]
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok
|
||||
--> src/main.rs:1:9
|
||||
|
|
||||
1 | #![deny(raw_pointer_derive)]
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
To fix this, either remove the lint or use the new name.
|
||||
|
||||
## safe-packed-borrows
|
||||
|
||||
This lint detects borrowing a field in the interior of a packed structure
|
||||
with alignment other than 1. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[repr(packed)]
|
||||
pub struct Unaligned<T>(pub T);
|
||||
|
||||
pub struct Foo {
|
||||
start: u8,
|
||||
data: Unaligned<u32>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Foo { start: 0, data: Unaligned(1) };
|
||||
let y = &x.data.0;
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: borrow of packed field requires unsafe function or block (error E0133)
|
||||
--> src/main.rs:11:13
|
||||
|
|
||||
11 | let y = &x.data.0;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(safe_packed_borrows)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
|
||||
```
|
||||
|
||||
## stable-features
|
||||
|
||||
This lint detects a `#[feature]` attribute that's since been made stable. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#![feature(test_accepted_feature)]
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: this feature has been stable since 1.0.0. Attribute no longer needed
|
||||
--> src/main.rs:1:12
|
||||
|
|
||||
1 | #![feature(test_accepted_feature)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
To fix, simply remove the `#![feature]` attribute, as it's no longer needed.
|
||||
|
||||
## type-alias-bounds
|
||||
|
||||
This lint detects bounds in type aliases. These are not currently enforced.
|
||||
Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#[allow(dead_code)]
|
||||
type SendVec<T: Send> = Vec<T>;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: bounds on generic parameters are not enforced in type aliases
|
||||
--> src/lib.rs:2:17
|
||||
|
|
||||
2 | type SendVec<T: Send> = Vec<T>;
|
||||
| ^^^^
|
||||
|
|
||||
= note: `#[warn(type_alias_bounds)]` on by default
|
||||
= help: the bound will not be checked when the type alias is used, and should be removed
|
||||
```
|
||||
|
||||
## tyvar-behind-raw-pointer
|
||||
|
||||
This lint detects raw pointer to an inference variable. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let data = std::ptr::null();
|
||||
let _ = &data as *const *const ();
|
||||
|
||||
if data.is_null() {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: type annotations needed
|
||||
--> src/main.rs:4:13
|
||||
|
|
||||
4 | if data.is_null() {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `#[warn(tyvar_behind_raw_pointer)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
|
||||
= note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
|
||||
```
|
||||
|
||||
## unconditional-recursion
|
||||
|
||||
This lint detects functions that cannot return without calling themselves.
|
||||
Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
fn foo() {
|
||||
foo();
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: function cannot return without recursing
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | fn foo() {
|
||||
| ^^^^^^^^ cannot return without recursing
|
||||
2 | foo();
|
||||
| ----- recursive call site
|
||||
|
|
||||
```
|
||||
|
||||
## unknown-lints
|
||||
|
||||
This lint detects unrecognized lint attribute. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust,ignore
|
||||
#[allow(not_a_real_lint)]
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unknown lint: `not_a_real_lint`
|
||||
--> src/main.rs:1:10
|
||||
|
|
||||
1 | #![allow(not_a_real_lint)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unreachable-code
|
||||
|
||||
This lint detects unreachable code paths. Some example code that
|
||||
triggers this lint:
|
||||
|
||||
```rust,no_run
|
||||
panic!("we never go past here!");
|
||||
|
||||
let x = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unreachable statement
|
||||
--> src/main.rs:4:5
|
||||
|
|
||||
4 | let x = 5;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unreachable-patterns
|
||||
|
||||
This lint detects unreachable patterns. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
match x {
|
||||
y => (),
|
||||
5 => (),
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unreachable pattern
|
||||
--> src/main.rs:5:5
|
||||
|
|
||||
5 | 5 => (),
|
||||
| ^
|
||||
|
|
||||
```
|
||||
|
||||
The `y` pattern will always match, so the five is impossible to reach.
|
||||
Remember, match arms match in order, you probably wanted to put the `5` case
|
||||
above the `y` case.
|
||||
|
||||
## unstable-name-collision
|
||||
|
||||
This lint detects that you've used a name that the standard library plans to
|
||||
add in the future, which means that your code may fail to compile without
|
||||
additional type annotations in the future. Either rename, or add those
|
||||
annotations now.
|
||||
|
||||
## unused-allocation
|
||||
|
||||
This lint detects unnecessary allocations that can be eliminated.
|
||||
|
||||
## unused-assignments
|
||||
|
||||
This lint detects assignments that will never be read. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
x = 6;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: value assigned to `x` is never read
|
||||
--> src/main.rs:4:5
|
||||
|
|
||||
4 | x = 6;
|
||||
| ^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-attributes
|
||||
|
||||
This lint detects attributes that were not used by the compiler. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
#![macro_export]
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unused attribute
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | #![macro_export]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-comparisons
|
||||
|
||||
This lint detects comparisons made useless by limits of the types involved. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
fn foo(x: u8) {
|
||||
x >= 0;
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: comparison is useless due to type limits
|
||||
--> src/main.rs:6:5
|
||||
|
|
||||
6 | x >= 0;
|
||||
| ^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-doc-comment
|
||||
|
||||
This lint detects doc comments that aren't used by rustdoc. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
/// docs for x
|
||||
let x = 12;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: doc comment not used by rustdoc
|
||||
--> src/main.rs:2:5
|
||||
|
|
||||
2 | /// docs for x
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-features
|
||||
|
||||
This lint detects unused or unknown features found in crate-level `#[feature]` directives.
|
||||
To fix this, simply remove the feature flag.
|
||||
|
||||
## unused-imports
|
||||
|
||||
This lint detects imports that are never used. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unused import: `std::collections::HashMap`
|
||||
--> src/main.rs:1:5
|
||||
|
|
||||
1 | use std::collections::HashMap;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-macros
|
||||
|
||||
This lint detects macros that were not used. Some example code that
|
||||
triggers this lint:
|
||||
|
||||
```rust
|
||||
macro_rules! unused {
|
||||
() => {};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unused macro definition
|
||||
--> src/main.rs:1:1
|
||||
|
|
||||
1 | / macro_rules! unused {
|
||||
2 | | () => {};
|
||||
3 | | }
|
||||
| |_^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-must-use
|
||||
|
||||
This lint detects unused result of a type flagged as `#[must_use]`. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
fn returns_result() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
returns_result();
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unused `std::result::Result` that must be used
|
||||
--> src/main.rs:6:5
|
||||
|
|
||||
6 | returns_result();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
```
|
||||
|
||||
## unused-mut
|
||||
|
||||
This lint detects mut variables which don't need to be mutable. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: variable does not need to be mutable
|
||||
--> src/main.rs:2:9
|
||||
|
|
||||
2 | let mut x = 5;
|
||||
| ----^
|
||||
| |
|
||||
| help: remove this `mut`
|
||||
|
|
||||
```
|
||||
|
||||
## unused-parens
|
||||
|
||||
This lint detects `if`, `match`, `while` and `return` with parentheses; they
|
||||
do not need them. Some example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
if(true) {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unnecessary parentheses around `if` condition
|
||||
--> src/main.rs:2:7
|
||||
|
|
||||
2 | if(true) {}
|
||||
| ^^^^^^ help: remove these parentheses
|
||||
|
|
||||
```
|
||||
|
||||
## unused-unsafe
|
||||
|
||||
This lint detects unnecessary use of an `unsafe` block. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
unsafe {}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unnecessary `unsafe` block
|
||||
--> src/main.rs:2:5
|
||||
|
|
||||
2 | unsafe {}
|
||||
| ^^^^^^ unnecessary `unsafe` block
|
||||
|
|
||||
```
|
||||
|
||||
## unused-variables
|
||||
|
||||
This lint detects variables which are not used in any way. Some
|
||||
example code that triggers this lint:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: unused variable: `x`
|
||||
--> src/main.rs:2:9
|
||||
|
|
||||
2 | let x = 5;
|
||||
| ^ help: consider using `_x` instead
|
||||
|
|
||||
```
|
||||
|
||||
## warnings
|
||||
|
||||
This lint is a bit special; by changing its level, you change every other warning
|
||||
that would produce a warning to whatever value you'd like:
|
||||
|
||||
```rust
|
||||
#![deny(warnings)]
|
||||
```
|
||||
|
||||
As such, you won't ever trigger this lint in your code directly.
|
||||
|
||||
## while-true
|
||||
|
||||
This lint detects `while true { }`. Some example code that triggers this
|
||||
lint:
|
||||
|
||||
```rust,no_run
|
||||
while true {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This will produce:
|
||||
|
||||
```text
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> src/main.rs:2:5
|
||||
|
|
||||
2 | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
```
|
||||
This file is auto-generated by the lint-docs script.
|
||||
|
@ -49,6 +49,30 @@ warning: missing documentation for a function
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
## missing_crate_level_docs
|
||||
|
||||
This lint is **allowed by default**. It detects if there is no documentation
|
||||
at the crate root. For example:
|
||||
|
||||
```rust
|
||||
#![warn(missing_crate_level_docs)]
|
||||
```
|
||||
|
||||
This will generate the following warning:
|
||||
|
||||
```text
|
||||
warning: no documentation found for this crate's top-level module
|
||||
|
|
||||
= help: The following guide may be of use:
|
||||
https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
|
||||
```
|
||||
|
||||
This is currently "allow" by default, but it is intended to make this a
|
||||
warning in the future. This is intended as a means to introduce new users on
|
||||
*how* to document their crate by pointing them to some instructions on how to
|
||||
get started, without providing overwhelming warnings like `missing_docs`
|
||||
might.
|
||||
|
||||
## missing_doc_code_examples
|
||||
|
||||
This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
|
||||
@ -117,3 +141,37 @@ warning: Documentation test in private item
|
||||
8 | | /// ```
|
||||
| |___________^
|
||||
```
|
||||
|
||||
## invalid_codeblock_attributes
|
||||
|
||||
This lint **warns by default**. It detects code block attributes in
|
||||
documentation examples that have potentially mis-typed values. For example:
|
||||
|
||||
```rust
|
||||
/// Example.
|
||||
///
|
||||
/// ```should-panic
|
||||
/// assert_eq!(1, 2);
|
||||
/// ```
|
||||
pub fn foo() {}
|
||||
```
|
||||
|
||||
Which will give:
|
||||
|
||||
```text
|
||||
warning: unknown attribute `should-panic`. Did you mean `should_panic`?
|
||||
--> src/lib.rs:1:1
|
||||
|
|
||||
1 | / /// Example.
|
||||
2 | | ///
|
||||
3 | | /// ```should-panic
|
||||
4 | | /// assert_eq!(1, 2);
|
||||
5 | | /// ```
|
||||
| |_______^
|
||||
|
|
||||
= note: `#[warn(invalid_codeblock_attributes)]` on by default
|
||||
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
|
||||
```
|
||||
|
||||
In the example above, the correct form is `should_panic`. This helps detect
|
||||
typo mistakes for some common attributes.
|
||||
|
13
src/tools/lint-docs/Cargo.toml
Normal file
13
src/tools/lint-docs/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "lint-docs"
|
||||
version = "0.1.0"
|
||||
authors = ["The Rust Project Developers"]
|
||||
edition = "2018"
|
||||
description = "A script to extract the lint documentation for the rustc book."
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.57"
|
||||
tempfile = "3.1.0"
|
||||
walkdir = "2.3.1"
|
114
src/tools/lint-docs/src/groups.rs
Normal file
114
src/tools/lint-docs/src/groups.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use crate::Lint;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::error::Error;
|
||||
use std::fmt::Write;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
|
||||
("unused", "Lints that detect things being declared but not used, or excess syntax"),
|
||||
("rustdoc", "Rustdoc-specific lints"),
|
||||
("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
|
||||
("nonstandard-style", "Violation of standard naming conventions"),
|
||||
("future-incompatible", "Lints that detect code that has future-compatibility problems"),
|
||||
("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
|
||||
];
|
||||
|
||||
/// Updates the documentation of lint groups.
|
||||
pub(crate) fn generate_group_docs(
|
||||
lints: &[Lint],
|
||||
rustc_path: &Path,
|
||||
out_path: &Path,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let groups = collect_groups(rustc_path)?;
|
||||
let groups_path = out_path.join("groups.md");
|
||||
let contents = fs::read_to_string(&groups_path)
|
||||
.map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
|
||||
let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
|
||||
// Delete the output because rustbuild uses hard links in its copies.
|
||||
let _ = fs::remove_file(&groups_path);
|
||||
fs::write(&groups_path, new_contents)
|
||||
.map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type LintGroups = BTreeMap<String, BTreeSet<String>>;
|
||||
|
||||
/// Collects the group names from rustc.
|
||||
fn collect_groups(rustc: &Path) -> Result<LintGroups, Box<dyn Error>> {
|
||||
let mut result = BTreeMap::new();
|
||||
let mut cmd = Command::new(rustc);
|
||||
cmd.arg("-Whelp");
|
||||
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
|
||||
output.status,
|
||||
std::str::from_utf8(&output.stderr).unwrap(),
|
||||
std::str::from_utf8(&output.stdout).unwrap(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
||||
let lines = stdout.lines();
|
||||
let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
|
||||
let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
|
||||
for line in table_start {
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
let mut parts = line.trim().splitn(2, ' ');
|
||||
let name = parts.next().expect("name in group");
|
||||
if name == "warnings" {
|
||||
// This is special.
|
||||
continue;
|
||||
}
|
||||
let lints =
|
||||
parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
|
||||
let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
|
||||
assert!(result.insert(name.to_string(), lints).is_none());
|
||||
}
|
||||
if result.is_empty() {
|
||||
return Err(
|
||||
format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
|
||||
);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
|
||||
let mut result = String::new();
|
||||
let mut to_link = Vec::new();
|
||||
result.push_str("| Group | Description | Lints |\n");
|
||||
result.push_str("|-------|-------------|-------|\n");
|
||||
result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
|
||||
for (group_name, group_lints) in groups {
|
||||
let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name)
|
||||
.ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
|
||||
.1;
|
||||
to_link.extend(group_lints);
|
||||
let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
|
||||
write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
|
||||
}
|
||||
result.push('\n');
|
||||
result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
|
||||
for lint_name in to_link {
|
||||
let lint_def =
|
||||
lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
|
||||
format!(
|
||||
"`rustc -W help` defined lint `{}` but that lint does not appear to exist",
|
||||
lint_name
|
||||
)
|
||||
})?;
|
||||
write!(
|
||||
result,
|
||||
"[{}]: listing/{}#{}\n",
|
||||
lint_name,
|
||||
lint_def.level.doc_filename(),
|
||||
lint_name
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Ok(result)
|
||||
}
|
472
src/tools/lint-docs/src/lib.rs
Normal file
472
src/tools/lint-docs/src/lib.rs
Normal file
@ -0,0 +1,472 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::Write;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
mod groups;
|
||||
|
||||
struct Lint {
|
||||
name: String,
|
||||
doc: Vec<String>,
|
||||
level: Level,
|
||||
path: PathBuf,
|
||||
lineno: usize,
|
||||
}
|
||||
|
||||
impl Lint {
|
||||
fn doc_contains(&self, text: &str) -> bool {
|
||||
self.doc.iter().any(|line| line.contains(text))
|
||||
}
|
||||
|
||||
fn is_ignored(&self) -> bool {
|
||||
self.doc
|
||||
.iter()
|
||||
.filter(|line| line.starts_with("```rust"))
|
||||
.all(|line| line.contains(",ignore"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum Level {
|
||||
Allow,
|
||||
Warn,
|
||||
Deny,
|
||||
}
|
||||
|
||||
impl Level {
|
||||
fn doc_filename(&self) -> &str {
|
||||
match self {
|
||||
Level::Allow => "allowed-by-default.md",
|
||||
Level::Warn => "warn-by-default.md",
|
||||
Level::Deny => "deny-by-default.md",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all lints, and writes the markdown documentation at the given directory.
|
||||
pub fn extract_lint_docs(
|
||||
src_path: &Path,
|
||||
out_path: &Path,
|
||||
rustc_path: &Path,
|
||||
verbose: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut lints = gather_lints(src_path)?;
|
||||
for lint in &mut lints {
|
||||
generate_output_example(lint, rustc_path, verbose).map_err(|e| {
|
||||
format!(
|
||||
"failed to test example in lint docs for `{}` in {}:{}: {}",
|
||||
lint.name,
|
||||
lint.path.display(),
|
||||
lint.lineno,
|
||||
e
|
||||
)
|
||||
})?;
|
||||
}
|
||||
save_lints_markdown(&lints, &out_path.join("listing"))?;
|
||||
groups::generate_group_docs(&lints, rustc_path, out_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Collects all lints from all files in the given directory.
|
||||
fn gather_lints(src_path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
|
||||
let mut lints = Vec::new();
|
||||
for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) {
|
||||
if !entry.path().extension().map_or(false, |ext| ext == "rs") {
|
||||
continue;
|
||||
}
|
||||
lints.extend(lints_from_file(entry.path())?);
|
||||
}
|
||||
if lints.is_empty() {
|
||||
return Err("no lints were found!".into());
|
||||
}
|
||||
Ok(lints)
|
||||
}
|
||||
|
||||
/// Collects all lints from the given file.
|
||||
fn lints_from_file(path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
|
||||
let mut lints = Vec::new();
|
||||
let contents = fs::read_to_string(path)
|
||||
.map_err(|e| format!("could not read {}: {}", path.display(), e))?;
|
||||
let mut lines = contents.lines().enumerate();
|
||||
loop {
|
||||
// Find a lint declaration.
|
||||
let lint_start = loop {
|
||||
match lines.next() {
|
||||
Some((lineno, line)) => {
|
||||
if line.trim().starts_with("declare_lint!") {
|
||||
break lineno + 1;
|
||||
}
|
||||
}
|
||||
None => return Ok(lints),
|
||||
}
|
||||
};
|
||||
// Read the lint.
|
||||
let mut doc_lines = Vec::new();
|
||||
let (doc, name) = loop {
|
||||
match lines.next() {
|
||||
Some((lineno, line)) => {
|
||||
let line = line.trim();
|
||||
if line.starts_with("/// ") {
|
||||
doc_lines.push(line.trim()[4..].to_string());
|
||||
} else if line.starts_with("///") {
|
||||
doc_lines.push("".to_string());
|
||||
} else if line.starts_with("// ") {
|
||||
// Ignore comments.
|
||||
continue;
|
||||
} else {
|
||||
let name = lint_name(line).map_err(|e| {
|
||||
format!(
|
||||
"could not determine lint name in {}:{}: {}, line was `{}`",
|
||||
path.display(),
|
||||
lineno,
|
||||
e,
|
||||
line
|
||||
)
|
||||
})?;
|
||||
if doc_lines.is_empty() {
|
||||
return Err(format!(
|
||||
"did not find doc lines for lint `{}` in {}",
|
||||
name,
|
||||
path.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
break (doc_lines, name);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(format!(
|
||||
"unexpected EOF for lint definition at {}:{}",
|
||||
path.display(),
|
||||
lint_start
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
// These lints are specifically undocumented. This should be reserved
|
||||
// for internal rustc-lints only.
|
||||
if name == "deprecated_in_future" {
|
||||
continue;
|
||||
}
|
||||
// Read the level.
|
||||
let level = loop {
|
||||
match lines.next() {
|
||||
// Ignore comments.
|
||||
Some((_, line)) if line.trim().starts_with("// ") => {}
|
||||
Some((lineno, line)) => match line.trim() {
|
||||
"Allow," => break Level::Allow,
|
||||
"Warn," => break Level::Warn,
|
||||
"Deny," => break Level::Deny,
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"unexpected lint level `{}` in {}:{}",
|
||||
line,
|
||||
path.display(),
|
||||
lineno
|
||||
)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(format!(
|
||||
"expected lint level in {}:{}, got EOF",
|
||||
path.display(),
|
||||
lint_start
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
// The rest of the lint definition is ignored.
|
||||
assert!(!doc.is_empty());
|
||||
lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the lint name (removing the visibility modifier, and checking validity).
|
||||
fn lint_name(line: &str) -> Result<String, &'static str> {
|
||||
// Skip over any potential `pub` visibility.
|
||||
match line.trim().split(' ').next_back() {
|
||||
Some(name) => {
|
||||
if !name.ends_with(',') {
|
||||
return Err("lint name should end with comma");
|
||||
}
|
||||
let name = &name[..name.len() - 1];
|
||||
if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
|
||||
return Err("lint name did not have expected format");
|
||||
}
|
||||
Ok(name.to_lowercase().to_string())
|
||||
}
|
||||
None => Err("could not find lint name"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutates the lint definition to replace the `{{produces}}` marker with the
|
||||
/// actual output from the compiler.
|
||||
fn generate_output_example(
|
||||
lint: &mut Lint,
|
||||
rustc_path: &Path,
|
||||
verbose: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Explicit list of lints that are allowed to not have an example. Please
|
||||
// try to avoid adding to this list.
|
||||
if matches!(
|
||||
lint.name.as_str(),
|
||||
"unused_features" // broken lint
|
||||
| "unstable_features" // deprecated
|
||||
) {
|
||||
return Ok(());
|
||||
}
|
||||
if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
|
||||
// Rustdoc lints are documented in the rustdoc book, don't check these.
|
||||
return Ok(());
|
||||
}
|
||||
check_style(lint)?;
|
||||
// Unfortunately some lints have extra requirements that this simple test
|
||||
// setup can't handle (like extern crates). An alternative is to use a
|
||||
// separate test suite, and use an include mechanism such as mdbook's
|
||||
// `{{#rustdoc_include}}`.
|
||||
if !lint.is_ignored() {
|
||||
replace_produces(lint, rustc_path, verbose)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks the doc style of the lint.
|
||||
fn check_style(lint: &Lint) -> Result<(), Box<dyn Error>> {
|
||||
for &expected in &["### Example", "### Explanation", "{{produces}}"] {
|
||||
if expected == "{{produces}}" && lint.is_ignored() {
|
||||
continue;
|
||||
}
|
||||
if !lint.doc_contains(expected) {
|
||||
return Err(format!("lint docs should contain the line `{}`", expected).into());
|
||||
}
|
||||
}
|
||||
if let Some(first) = lint.doc.first() {
|
||||
if !first.starts_with(&format!("The `{}` lint", lint.name)) {
|
||||
return Err(format!(
|
||||
"lint docs should start with the text \"The `{}` lint\" to introduce the lint",
|
||||
lint.name
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
|
||||
/// output from the compiler.
|
||||
fn replace_produces(
|
||||
lint: &mut Lint,
|
||||
rustc_path: &Path,
|
||||
verbose: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut lines = lint.doc.iter_mut();
|
||||
loop {
|
||||
// Find start of example.
|
||||
let options = loop {
|
||||
match lines.next() {
|
||||
Some(line) if line.starts_with("```rust") => {
|
||||
break line[7..].split(',').collect::<Vec<_>>();
|
||||
}
|
||||
Some(line) if line.contains("{{produces}}") => {
|
||||
return Err("lint marker {{{{produces}}}} found, \
|
||||
but expected to immediately follow a rust code block"
|
||||
.into());
|
||||
}
|
||||
Some(_) => {}
|
||||
None => return Ok(()),
|
||||
}
|
||||
};
|
||||
// Find the end of example.
|
||||
let mut example = Vec::new();
|
||||
loop {
|
||||
match lines.next() {
|
||||
Some(line) if line == "```" => break,
|
||||
Some(line) => example.push(line),
|
||||
None => {
|
||||
return Err(format!(
|
||||
"did not find end of example triple ticks ```, docs were:\n{:?}",
|
||||
lint.doc
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find the {{produces}} line.
|
||||
loop {
|
||||
match lines.next() {
|
||||
Some(line) if line.is_empty() => {}
|
||||
Some(line) if line == "{{produces}}" => {
|
||||
let output =
|
||||
generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?;
|
||||
line.replace_range(
|
||||
..,
|
||||
&format!(
|
||||
"This will produce:\n\
|
||||
\n\
|
||||
```text\n\
|
||||
{}\
|
||||
```",
|
||||
output
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
// No {{produces}} after example, find next example.
|
||||
Some(_line) => break,
|
||||
None => return Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the compiler against the example, and extracts the output.
|
||||
fn generate_lint_output(
|
||||
name: &str,
|
||||
example: &[&mut String],
|
||||
options: &[&str],
|
||||
rustc_path: &Path,
|
||||
verbose: bool,
|
||||
) -> Result<String, Box<dyn Error>> {
|
||||
if verbose {
|
||||
eprintln!("compiling lint {}", name);
|
||||
}
|
||||
let tempdir = tempfile::TempDir::new()?;
|
||||
let tempfile = tempdir.path().join("lint_example.rs");
|
||||
let mut source = String::new();
|
||||
let needs_main = !example.iter().any(|line| line.contains("fn main"));
|
||||
// Remove `# ` prefix for hidden lines.
|
||||
let unhidden =
|
||||
example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line });
|
||||
let mut lines = unhidden.peekable();
|
||||
while let Some(line) = lines.peek() {
|
||||
if line.starts_with("#!") {
|
||||
source.push_str(line);
|
||||
source.push('\n');
|
||||
lines.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if needs_main {
|
||||
source.push_str("fn main() {\n");
|
||||
}
|
||||
for line in lines {
|
||||
source.push_str(line);
|
||||
source.push('\n')
|
||||
}
|
||||
if needs_main {
|
||||
source.push_str("}\n");
|
||||
}
|
||||
fs::write(&tempfile, source)
|
||||
.map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
|
||||
let mut cmd = Command::new(rustc_path);
|
||||
if options.contains(&"edition2015") {
|
||||
cmd.arg("--edition=2015");
|
||||
} else {
|
||||
cmd.arg("--edition=2018");
|
||||
}
|
||||
cmd.arg("--error-format=json");
|
||||
if options.contains(&"test") {
|
||||
cmd.arg("--test");
|
||||
}
|
||||
cmd.arg("lint_example.rs");
|
||||
cmd.current_dir(tempdir.path());
|
||||
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
|
||||
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||
let msgs = stderr
|
||||
.lines()
|
||||
.filter(|line| line.starts_with('{'))
|
||||
.map(serde_json::from_str)
|
||||
.collect::<Result<Vec<serde_json::Value>, _>>()?;
|
||||
match msgs
|
||||
.iter()
|
||||
.find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
|
||||
{
|
||||
Some(msg) => {
|
||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
||||
Ok(rendered.to_string())
|
||||
}
|
||||
None => {
|
||||
match msgs.iter().find(
|
||||
|msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
|
||||
) {
|
||||
Some(msg) => {
|
||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
||||
Ok(rendered.to_string())
|
||||
}
|
||||
None => {
|
||||
let rendered: Vec<&str> =
|
||||
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
|
||||
Err(format!(
|
||||
"did not find lint `{}` in output of example, got:\n{}",
|
||||
name,
|
||||
rendered.join("\n")
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ALLOWED_MD: &str = r#"# Allowed-by-default lints
|
||||
|
||||
These lints are all set to the 'allow' level by default. As such, they won't show up
|
||||
unless you set them to a higher lint level with a flag or attribute.
|
||||
|
||||
"#;
|
||||
|
||||
static WARN_MD: &str = r#"# Warn-by-default lints
|
||||
|
||||
These lints are all set to the 'warn' level by default.
|
||||
|
||||
"#;
|
||||
|
||||
static DENY_MD: &str = r#"# Deny-by-default lints
|
||||
|
||||
These lints are all set to the 'deny' level by default.
|
||||
|
||||
"#;
|
||||
|
||||
/// Saves the mdbook lint chapters at the given path.
|
||||
fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box<dyn Error>> {
|
||||
save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?;
|
||||
save_level(lints, Level::Warn, out_dir, WARN_MD)?;
|
||||
save_level(lints, Level::Deny, out_dir, DENY_MD)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_level(
|
||||
lints: &[Lint],
|
||||
level: Level,
|
||||
out_dir: &Path,
|
||||
header: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut result = String::new();
|
||||
result.push_str(header);
|
||||
let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
|
||||
these_lints.sort_unstable_by_key(|lint| &lint.name);
|
||||
for lint in &these_lints {
|
||||
write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
|
||||
}
|
||||
result.push('\n');
|
||||
for lint in &these_lints {
|
||||
write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
|
||||
for line in &lint.doc {
|
||||
result.push_str(line);
|
||||
result.push('\n');
|
||||
}
|
||||
result.push('\n');
|
||||
}
|
||||
let out_path = out_dir.join(level.doc_filename());
|
||||
// Delete the output because rustbuild uses hard links in its copies.
|
||||
let _ = fs::remove_file(&out_path);
|
||||
fs::write(&out_path, result)
|
||||
.map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
|
||||
Ok(())
|
||||
}
|
56
src/tools/lint-docs/src/main.rs
Normal file
56
src/tools/lint-docs/src/main.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = doit() {
|
||||
println!("error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn doit() -> Result<(), Box<dyn Error>> {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let mut src_path = None;
|
||||
let mut out_path = None;
|
||||
let mut rustc_path = None;
|
||||
let mut verbose = false;
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--src" => {
|
||||
src_path = match args.next() {
|
||||
Some(s) => Some(PathBuf::from(s)),
|
||||
None => return Err("--src requires a value".into()),
|
||||
};
|
||||
}
|
||||
"--out" => {
|
||||
out_path = match args.next() {
|
||||
Some(s) => Some(PathBuf::from(s)),
|
||||
None => return Err("--out requires a value".into()),
|
||||
};
|
||||
}
|
||||
"--rustc" => {
|
||||
rustc_path = match args.next() {
|
||||
Some(s) => Some(PathBuf::from(s)),
|
||||
None => return Err("--rustc requires a value".into()),
|
||||
};
|
||||
}
|
||||
"-v" | "--verbose" => verbose = true,
|
||||
s => return Err(format!("unexpected argument `{}`", s).into()),
|
||||
}
|
||||
}
|
||||
if src_path.is_none() {
|
||||
return Err("--src must be specified to the directory with the compiler source".into());
|
||||
}
|
||||
if out_path.is_none() {
|
||||
return Err("--out must be specified to the directory with the lint listing docs".into());
|
||||
}
|
||||
if rustc_path.is_none() {
|
||||
return Err("--rustc must be specified to the path of rustc".into());
|
||||
}
|
||||
lint_docs::extract_lint_docs(
|
||||
&src_path.unwrap(),
|
||||
&out_path.unwrap(),
|
||||
&rustc_path.unwrap(),
|
||||
verbose,
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user