Auto merge of #92883 - matthiaskrgr:rollup-uoudywx, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #92045 (Don't fall back to crate-level opaque type definitions.) - #92381 (Suggest `return`ing tail expressions in async functions) - #92768 (Partially stabilize `maybe_uninit_extra`) - #92810 (Deduplicate box deref and regular deref suggestions) - #92818 (Update documentation for doc_cfg feature) - #92840 (Fix some lints documentation) - #92849 (Clippyup) - #92854 (Use the updated Rust logo in rustdoc) - #92864 (Fix a missing dot in the main item heading) Failed merges: - #92838 (Clean up some links in RELEASES) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ad46af2471
@ -639,7 +639,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.14.0",
|
||||
"clippy_lints",
|
||||
@ -647,6 +647,7 @@ dependencies = [
|
||||
"compiletest_rs",
|
||||
"derive-new",
|
||||
"filetime",
|
||||
"futures 0.3.12",
|
||||
"if_chain",
|
||||
"itertools 0.10.1",
|
||||
"parking_lot",
|
||||
@ -659,6 +660,7 @@ dependencies = [
|
||||
"syn",
|
||||
"tempfile",
|
||||
"tester",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -678,7 +680,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.14.0",
|
||||
"clippy_utils",
|
||||
@ -699,8 +701,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"if_chain",
|
||||
"rustc-semver",
|
||||
]
|
||||
|
@ -10,7 +10,6 @@ pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
|
||||
|
||||
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
|
||||
|
||||
use hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::undo_log::Rollback;
|
||||
@ -291,7 +290,12 @@ pub struct InferCtxt<'a, 'tcx> {
|
||||
|
||||
/// The `DefId` of the item in whose context we are performing inference or typeck.
|
||||
/// It is used to check whether an opaque type use is a defining use.
|
||||
pub defining_use_anchor: LocalDefId,
|
||||
///
|
||||
/// If it is `None`, we can't resolve opaque types here and need to bubble up
|
||||
/// the obligation. This frequently happens for
|
||||
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
|
||||
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
|
||||
pub defining_use_anchor: Option<LocalDefId>,
|
||||
|
||||
/// During type-checking/inference of a body, `in_progress_typeck_results`
|
||||
/// contains a reference to the typeck results being built up, which are
|
||||
@ -547,7 +551,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
|
||||
pub struct InferCtxtBuilder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
|
||||
defining_use_anchor: LocalDefId,
|
||||
defining_use_anchor: Option<LocalDefId>,
|
||||
}
|
||||
|
||||
pub trait TyCtxtInferExt<'tcx> {
|
||||
@ -556,11 +560,7 @@ pub trait TyCtxtInferExt<'tcx> {
|
||||
|
||||
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
||||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
defining_use_anchor: CRATE_DEF_ID,
|
||||
fresh_typeck_results: None,
|
||||
}
|
||||
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
/// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
|
||||
/// in mir borrowck.
|
||||
pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
|
||||
self.defining_use_anchor = defining_use_anchor;
|
||||
self.defining_use_anchor = Some(defining_use_anchor);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -328,6 +328,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
|
||||
let tcx = self.tcx;
|
||||
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let parent_def_id = self.defining_use_anchor?;
|
||||
let item_kind = &tcx.hir().expect_item(def_id).kind;
|
||||
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"weird opaque type: {:#?}",
|
||||
item_kind
|
||||
)
|
||||
};
|
||||
let in_definition_scope = match *origin {
|
||||
// Async `impl Trait`
|
||||
hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
|
||||
// Anonymous `impl Trait`
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||
// Named `type Foo = impl Bar;`
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
|
||||
}
|
||||
};
|
||||
in_definition_scope.then_some(*origin)
|
||||
}
|
||||
}
|
||||
|
||||
// Visitor that requires that (almost) all regions in the type visited outlive
|
||||
@ -459,31 +484,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
// }
|
||||
// ```
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let parent_def_id = self.infcx.defining_use_anchor;
|
||||
let item_kind = &tcx.hir().expect_item(def_id).kind;
|
||||
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
|
||||
span_bug!(
|
||||
self.value_span,
|
||||
"weird opaque type: {:#?}, {:#?}",
|
||||
ty.kind(),
|
||||
item_kind
|
||||
)
|
||||
};
|
||||
let in_definition_scope = match *origin {
|
||||
// Async `impl Trait`
|
||||
hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
|
||||
// Anonymous `impl Trait`
|
||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||
// Named `type Foo = impl Bar;`
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
|
||||
}
|
||||
};
|
||||
if in_definition_scope {
|
||||
if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
|
||||
let opaque_type_key =
|
||||
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
|
||||
return self.fold_opaque_ty(ty, opaque_type_key, *origin);
|
||||
return self.fold_opaque_ty(ty, opaque_type_key, origin);
|
||||
}
|
||||
|
||||
debug!(
|
||||
|
@ -1805,7 +1805,7 @@ declare_lint! {
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// if let _ = 123 {
|
||||
/// println!("always runs!");
|
||||
/// }
|
||||
@ -2431,7 +2431,19 @@ declare_lint! {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: formatting may not be suitable for sub-register argument
|
||||
/// --> src/main.rs:7:19
|
||||
/// |
|
||||
/// 7 | asm!("mov {0}, {0}", in(reg) 0i16);
|
||||
/// | ^^^ ^^^ ---- for this argument
|
||||
/// |
|
||||
/// = note: `#[warn(asm_sub_register)]` on by default
|
||||
/// = help: use the `x` modifier to have the register formatted as `ax`
|
||||
/// = help: or use the `r` modifier to keep the default formatting of `rax`
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
@ -2470,7 +2482,17 @@ declare_lint! {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
|
||||
/// --> src/main.rs:8:14
|
||||
/// |
|
||||
/// 8 | ".att_syntax",
|
||||
/// | ^^^^^^^^^^^
|
||||
/// |
|
||||
/// = note: `#[warn(bad_asm_style)]` on by default
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
@ -2788,7 +2810,7 @@ declare_lint! {
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// ```rust,compile_fail
|
||||
/// #![feature(staged_api)]
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
@ -3618,7 +3640,17 @@ declare_lint! {
|
||||
/// fn foo() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: duplicated attribute
|
||||
/// --> src/lib.rs:2:1
|
||||
/// |
|
||||
/// 2 | #[test]
|
||||
/// | ^^^^^^^
|
||||
/// |
|
||||
/// = note: `#[warn(duplicate_macro_attributes)]` on by default
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
|
@ -31,9 +31,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
error: TypeError<'tcx>,
|
||||
) {
|
||||
self.annotate_expected_due_to_let_ty(err, expr, error);
|
||||
self.suggest_box_deref(err, expr, expected, expr_ty);
|
||||
self.suggest_compatible_variants(err, expr, expected, expr_ty);
|
||||
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
|
||||
self.suggest_compatible_variants(err, expr, expected, expr_ty);
|
||||
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
|
||||
return;
|
||||
}
|
||||
@ -259,23 +258,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_box_deref(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
expected: Ty<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
) {
|
||||
if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"try dereferencing the `Box`",
|
||||
"*".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// If the expected type is an enum (Issue #55250) with any variants whose
|
||||
/// sole field is of the found type, suggest such variants. (Issue #42764)
|
||||
fn suggest_compatible_variants(
|
||||
@ -857,14 +839,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Applicability::MachineApplicable,
|
||||
false,
|
||||
));
|
||||
} else if self.infcx.type_is_copy_modulo_regions(
|
||||
self.param_env,
|
||||
expected,
|
||||
sp,
|
||||
) {
|
||||
// For this suggestion to make sense, the type would need to be `Copy`.
|
||||
}
|
||||
|
||||
// For this suggestion to make sense, the type would need to be `Copy`,
|
||||
// or we have to be moving out of a `Box<T>`
|
||||
if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
|
||||
|| checked_ty.is_box()
|
||||
{
|
||||
if let Ok(code) = sm.span_to_snippet(expr.span) {
|
||||
let message = if checked_ty.is_region_ptr() {
|
||||
let message = if checked_ty.is_box() {
|
||||
"consider unboxing the value"
|
||||
} else if checked_ty.is_region_ptr() {
|
||||
"consider dereferencing the borrow"
|
||||
} else {
|
||||
"consider dereferencing the type"
|
||||
|
@ -9,7 +9,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Binder, Ty};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
@ -608,6 +608,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let bound_vars = self.tcx.late_bound_vars(fn_id);
|
||||
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
||||
let ty = self.normalize_associated_types_in(expr.span, ty);
|
||||
let ty = match self.tcx.asyncness(fn_id.owner) {
|
||||
hir::IsAsync::Async => self.tcx.infer_ctxt().enter(|infcx| {
|
||||
infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
fn_decl.output.span(),
|
||||
"failed to get output type of async function"
|
||||
)
|
||||
})
|
||||
}),
|
||||
hir::IsAsync::NotAsync => ty,
|
||||
};
|
||||
if self.can_coerce(found, ty) {
|
||||
err.multipart_suggestion(
|
||||
"you might have meant to return this value",
|
||||
|
@ -119,7 +119,6 @@
|
||||
#![feature(inplace_iteration)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(layout_for_ptr)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![cfg_attr(test, feature(new_uninit))]
|
||||
#![feature(nonnull_slice_from_raw_parts)]
|
||||
|
@ -330,7 +330,7 @@ impl<T> MaybeUninit<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)]
|
||||
/// #![feature(maybe_uninit_uninit_array, maybe_uninit_slice)]
|
||||
///
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
@ -662,7 +662,6 @@ impl<T> MaybeUninit<T> {
|
||||
/// Correct usage of this method:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(maybe_uninit_extra)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<u32>::uninit();
|
||||
@ -683,7 +682,6 @@ impl<T> MaybeUninit<T> {
|
||||
/// *Incorrect* usage of this method:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// #![feature(maybe_uninit_extra)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
|
||||
@ -693,8 +691,8 @@ impl<T> MaybeUninit<T> {
|
||||
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
|
||||
/// // they both get dropped!
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
|
||||
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init_read", issue = "63567")]
|
||||
#[inline(always)]
|
||||
#[track_caller]
|
||||
pub const unsafe fn assume_init_read(&self) -> T {
|
||||
@ -728,7 +726,7 @@ impl<T> MaybeUninit<T> {
|
||||
///
|
||||
/// [`assume_init`]: MaybeUninit::assume_init
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
|
||||
pub unsafe fn assume_init_drop(&mut self) {
|
||||
// SAFETY: the caller must guarantee that `self` is initialized and
|
||||
// satisfies all invariants of `T`.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_maybe_uninit_assume_init)]
|
||||
#![feature(const_maybe_uninit_assume_init_read)]
|
||||
#![feature(const_num_from_num)]
|
||||
#![feature(const_ptr_read)]
|
||||
#![feature(const_ptr_write)]
|
||||
@ -46,7 +47,6 @@
|
||||
#![feature(slice_take)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_array_assume_init)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(numfmt)]
|
||||
|
@ -297,7 +297,6 @@
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
|
@ -84,6 +84,39 @@ in documentation.
|
||||
`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
|
||||
Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
|
||||
|
||||
### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
|
||||
|
||||
`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
|
||||
`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
|
||||
previous source code:
|
||||
|
||||
```rust
|
||||
#![feature(doc_auto_cfg)]
|
||||
|
||||
/// Token struct that can only be used on Windows.
|
||||
#[cfg(any(windows, doc))]
|
||||
pub struct WindowsToken;
|
||||
|
||||
/// Token struct that can only be used on Unix.
|
||||
#[cfg(any(unix, doc))]
|
||||
pub struct UnixToken;
|
||||
|
||||
/// Token struct that is only available with the `serde` feature
|
||||
#[cfg(feature = "serde")]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct SerdeToken;
|
||||
```
|
||||
|
||||
It'll render almost the same, the difference being that `doc` will also be displayed. To fix this,
|
||||
you can use `doc_cfg_hide`:
|
||||
|
||||
```rust
|
||||
#![feature(doc_cfg_hide)]
|
||||
#![doc(cfg_hide(doc))]
|
||||
```
|
||||
|
||||
And `doc` won't show up anymore!
|
||||
|
||||
[cfg-doc]: ./advanced-features.md
|
||||
[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
|
||||
[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
|
||||
|
@ -240,7 +240,7 @@ pub(super) fn write_shared(
|
||||
}
|
||||
|
||||
if (*cx.shared).layout.logo.is_empty() {
|
||||
write_toolchain("rust-logo.png", static_files::RUST_LOGO)?;
|
||||
write_toolchain("rust-logo.svg", static_files::RUST_LOGO_SVG)?;
|
||||
}
|
||||
if (*cx.shared).layout.favicon.is_empty() {
|
||||
write_toolchain("favicon.svg", static_files::RUST_FAVICON_SVG)?;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 715 B |
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.6 KiB |
61
src/librustdoc/html/static/images/rust-logo.svg
Normal file
61
src/librustdoc/html/static/images/rust-logo.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<svg version="1.1" height="106" width="106" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="logo" transform="translate(53, 53)">
|
||||
<path id="r" transform="translate(0.5, 0.5)" stroke="black" stroke-width="1" stroke-linejoin="round" d="
|
||||
M -9,-15 H 4 C 12,-15 12,-7 4,-7 H -9 Z
|
||||
M -40,22 H 0 V 11 H -9 V 3 H 1 C 12,3 6,22 15,22 H 40
|
||||
V 3 H 34 V 5 C 34,13 25,12 24,7 C 23,2 19,-2 18,-2 C 33,-10 24,-26 12,-26 H -35
|
||||
V -15 H -25 V 11 H -40 Z" />
|
||||
<g id="gear" mask="url(#holes)">
|
||||
<circle r="43" fill="none" stroke="black" stroke-width="9" />
|
||||
<g id="cogs">
|
||||
<polygon id="cog" stroke="black" stroke-width="3" stroke-linejoin="round" points="46,3 51,0 46,-3" />
|
||||
<use xlink:href="#cog" transform="rotate(11.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(22.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(33.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(45.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(56.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(67.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(78.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(90.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(101.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(112.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(123.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(135.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(146.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(157.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(168.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(180.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(191.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(202.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(213.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(225.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(236.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(247.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(258.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(270.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(281.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(292.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(303.75)" />
|
||||
<use xlink:href="#cog" transform="rotate(315.00)" />
|
||||
<use xlink:href="#cog" transform="rotate(326.25)" />
|
||||
<use xlink:href="#cog" transform="rotate(337.50)" />
|
||||
<use xlink:href="#cog" transform="rotate(348.75)" />
|
||||
</g>
|
||||
<g id="mounts">
|
||||
<polygon id="mount" stroke="black" stroke-width="6" stroke-linejoin="round" points="-7,-42 0,-35 7,-42" />
|
||||
<use xlink:href="#mount" transform="rotate(72)" />
|
||||
<use xlink:href="#mount" transform="rotate(144)" />
|
||||
<use xlink:href="#mount" transform="rotate(216)" />
|
||||
<use xlink:href="#mount" transform="rotate(288)" />
|
||||
</g>
|
||||
</g>
|
||||
<mask id="holes">
|
||||
<rect x="-60" y="-60" width="120" height="120" fill="white"/>
|
||||
<circle id="hole" cy="-40" r="3" />
|
||||
<use xlink:href="#hole" transform="rotate(72)" />
|
||||
<use xlink:href="#hole" transform="rotate(144)" />
|
||||
<use xlink:href="#hole" transform="rotate(216)" />
|
||||
<use xlink:href="#hole" transform="rotate(288)" />
|
||||
</mask>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
@ -67,8 +67,9 @@ crate static LICENSE_APACHE: &[u8] = include_bytes!("static/LICENSE-APACHE.txt")
|
||||
/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
|
||||
crate static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt");
|
||||
|
||||
/// The contents of `rust-logo.png`, the default icon of the documentation.
|
||||
crate static RUST_LOGO: &[u8] = include_bytes!("static/images/rust-logo.png");
|
||||
/// The contents of `rust-logo.svg`, the default icon of the documentation.
|
||||
crate static RUST_LOGO_SVG: &[u8] = include_bytes!("static/images/rust-logo.svg");
|
||||
|
||||
/// The default documentation favicons (SVG and PNG fallbacks)
|
||||
crate static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/images/favicon.svg");
|
||||
crate static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/images/favicon-16x16.png");
|
||||
|
@ -79,7 +79,7 @@
|
||||
{%- if !layout.logo.is_empty() %}
|
||||
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
||||
{%- else -%}
|
||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
|
||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
|
||||
{%- endif -%}
|
||||
</div>
|
||||
</a> {#- -#}
|
||||
@ -92,7 +92,7 @@
|
||||
{%- if !layout.logo.is_empty() %}
|
||||
<img src="{{layout.logo}}" alt="logo"> {#- -#}
|
||||
{%- else -%}
|
||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
|
||||
<img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
|
||||
{%- endif -%}
|
||||
</a> {#- -#}
|
||||
<nav class="sub"> {#- -#}
|
||||
|
@ -16,12 +16,12 @@
|
||||
</h1> {#- -#}
|
||||
<span class="out-of-band"> {#- -#}
|
||||
{% if !stability_since_raw.is_empty() %}
|
||||
{{- stability_since_raw|safe -}} ·
|
||||
{{- stability_since_raw|safe -}} · {# -#}
|
||||
{% endif %}
|
||||
{%- match src_href -%}
|
||||
{%- when Some with (href) -%}
|
||||
<a class="srclink" href="{{href|safe}}" title="goto source code">source</a>
|
||||
{%- else -%} ·
|
||||
<a class="srclink" href="{{href|safe}}" title="goto source code">source</a> · {# -#}
|
||||
{%- else -%}
|
||||
{%- endmatch -%}
|
||||
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
|
||||
[<span class="inner">−</span>] {#- -#}
|
||||
|
@ -2,9 +2,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/infinite-autoderef.rs:20:13
|
||||
|
|
||||
LL | x = Box::new(x);
|
||||
| ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| cyclic type of infinite size
|
||||
| ^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | x = *Box::new(x);
|
||||
| +
|
||||
|
||||
error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
|
||||
--> $DIR/infinite-autoderef.rs:25:5
|
||||
|
@ -2,9 +2,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/occurs-check-2.rs:7:9
|
||||
|
|
||||
LL | f = Box::new(g);
|
||||
| ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| cyclic type of infinite size
|
||||
| ^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | f = *Box::new(g);
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,9 +2,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/occurs-check.rs:5:9
|
||||
|
|
||||
LL | f = Box::new(f);
|
||||
| ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| cyclic type of infinite size
|
||||
| ^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | f = *Box::new(f);
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,3 +1,16 @@
|
||||
// > Suggest `return`ing tail expressions that match return type
|
||||
// >
|
||||
// > Some newcomers are confused by the behavior of tail expressions,
|
||||
// > interpreting that "leaving out the `;` makes it the return value".
|
||||
// > To help them go in the right direction, suggest using `return` instead
|
||||
// > when applicable.
|
||||
// (original commit description for this test)
|
||||
//
|
||||
// This test was amended to also serve as a regression test for #92308, where
|
||||
// this suggestion would not trigger with async functions.
|
||||
//
|
||||
// edition:2018
|
||||
|
||||
fn main() {
|
||||
let _ = foo(true);
|
||||
}
|
||||
@ -5,6 +18,15 @@ fn main() {
|
||||
fn foo(x: bool) -> Result<f64, i32> {
|
||||
if x {
|
||||
Err(42) //~ ERROR mismatched types
|
||||
//| HELP you might have meant to return this value
|
||||
}
|
||||
Ok(42.0)
|
||||
}
|
||||
|
||||
async fn bar(x: bool) -> Result<f64, i32> {
|
||||
if x {
|
||||
Err(42) //~ ERROR mismatched types
|
||||
//| HELP you might have meant to return this value
|
||||
}
|
||||
Ok(42.0)
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/tail-expr-as-potential-return.rs:7:9
|
||||
--> $DIR/tail-expr-as-potential-return.rs:28:9
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | Err(42)
|
||||
| | ^^^^^^^ expected `()`, found enum `Result`
|
||||
LL | | //| HELP you might have meant to return this value
|
||||
LL | | }
|
||||
| |_____- expected this to be `()`
|
||||
|
|
||||
@ -14,6 +15,23 @@ help: you might have meant to return this value
|
||||
LL | return Err(42);
|
||||
| ++++++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/tail-expr-as-potential-return.rs:20:9
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | Err(42)
|
||||
| | ^^^^^^^ expected `()`, found enum `Result`
|
||||
LL | | //| HELP you might have meant to return this value
|
||||
LL | | }
|
||||
| |_____- expected this to be `()`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found enum `Result<_, {integer}>`
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | return Err(42);
|
||||
| ++++++ +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -38,9 +38,12 @@ error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:17:9
|
||||
|
|
||||
LL | f = Box::new(f);
|
||||
| ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
|
||||
| |
|
||||
| cyclic type of infinite size
|
||||
| ^^^^^^^^^^^ cyclic type of infinite size
|
||||
|
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | f = *Box::new(f);
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-suggestions.rs:21:9
|
||||
|
@ -8,7 +8,7 @@ fn foo(x: Ty) -> Ty {
|
||||
Ty::Unit => Ty::Unit,
|
||||
Ty::List(elem) => foo(elem),
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP try dereferencing the `Box`
|
||||
//~| HELP consider unboxing the value
|
||||
//~| HELP try wrapping
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ LL | Ty::List(elem) => foo(elem),
|
||||
|
|
||||
= note: expected enum `Ty`
|
||||
found struct `Box<Ty>`
|
||||
help: try dereferencing the `Box`
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | Ty::List(elem) => foo(*elem),
|
||||
| +
|
||||
|
@ -6,7 +6,7 @@ LL | want_foo(b);
|
||||
|
|
||||
= note: expected struct `Foo`
|
||||
found struct `Box<Foo>`
|
||||
help: try dereferencing the `Box`
|
||||
help: consider unboxing the value
|
||||
|
|
||||
LL | want_foo(*b);
|
||||
| +
|
||||
|
@ -2,9 +2,12 @@
|
||||
uitest = "test --test compile-test"
|
||||
dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
|
||||
lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
|
||||
collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
|
||||
collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored"
|
||||
|
||||
[build]
|
||||
# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
|
||||
rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
|
||||
target-dir = "target"
|
||||
|
||||
[unstable]
|
||||
binary-dep-depinfo = true
|
||||
|
16
src/tools/clippy/.github/workflows/clippy.yml
vendored
16
src/tools/clippy/.github/workflows/clippy.yml
vendored
@ -49,17 +49,17 @@ jobs:
|
||||
echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo build --features deny-warnings,internal
|
||||
|
||||
- name: Test
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo test --features deny-warnings,internal
|
||||
|
||||
- name: Test clippy_lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo test --features deny-warnings,internal
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test clippy_utils
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo test --features deny-warnings,internal
|
||||
working-directory: clippy_utils
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
@ -70,14 +70,6 @@ jobs:
|
||||
run: cargo test --features deny-warnings
|
||||
working-directory: clippy_dev
|
||||
|
||||
- name: Test cargo-clippy
|
||||
run: ../target/debug/cargo-clippy
|
||||
working-directory: clippy_workspace_tests
|
||||
|
||||
- name: Test cargo-clippy --fix
|
||||
run: ../target/debug/cargo-clippy clippy --fix
|
||||
working-directory: clippy_workspace_tests
|
||||
|
||||
- name: Test clippy-driver
|
||||
run: bash .github/driver.sh
|
||||
env:
|
||||
|
@ -112,17 +112,22 @@ jobs:
|
||||
echo "$SYSROOT/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Build
|
||||
run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo build --features deny-warnings,internal
|
||||
|
||||
- name: Test
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo test --features deny-warnings,internal
|
||||
|
||||
- name: Test
|
||||
if: runner.os != 'Linux'
|
||||
run: cargo test --features deny-warnings,internal -- --skip dogfood
|
||||
|
||||
- name: Test clippy_lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo test --features deny-warnings,internal
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test clippy_utils
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
run: cargo test --features deny-warnings,internal
|
||||
working-directory: clippy_utils
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
@ -133,14 +138,6 @@ jobs:
|
||||
run: cargo test --features deny-warnings
|
||||
working-directory: clippy_dev
|
||||
|
||||
- name: Test cargo-clippy
|
||||
run: ../target/debug/cargo-clippy
|
||||
working-directory: clippy_workspace_tests
|
||||
|
||||
- name: Test cargo-clippy --fix
|
||||
run: ../target/debug/cargo-clippy clippy --fix
|
||||
working-directory: clippy_workspace_tests
|
||||
|
||||
- name: Test clippy-driver
|
||||
run: bash .github/driver.sh
|
||||
env:
|
||||
|
1
src/tools/clippy/.gitignore
vendored
1
src/tools/clippy/.gitignore
vendored
@ -19,7 +19,6 @@ out
|
||||
/target
|
||||
/clippy_lints/target
|
||||
/clippy_utils/target
|
||||
/clippy_workspace_tests/target
|
||||
/clippy_dev/target
|
||||
/lintcheck/target
|
||||
/rustc_tools_util/target
|
||||
|
@ -2887,6 +2887,7 @@ Released 2018-09-13
|
||||
[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
|
||||
[`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
|
||||
[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
|
||||
[`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
|
||||
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
|
||||
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
|
||||
[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
|
||||
@ -3070,6 +3071,7 @@ Released 2018-09-13
|
||||
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
|
||||
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
|
||||
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
|
||||
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
|
||||
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
|
||||
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
||||
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
||||
@ -3253,6 +3255,7 @@ Released 2018-09-13
|
||||
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
|
||||
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
|
||||
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
|
||||
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
|
||||
[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
|
||||
[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
|
||||
[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
@ -47,7 +47,9 @@ itertools = "0.10"
|
||||
quote = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
syn = { version = "1.0", features = ["full"] }
|
||||
futures = "0.3"
|
||||
parking_lot = "0.11.2"
|
||||
tokio = { version = "1", features = ["io-util"] }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
|
||||
@ -55,8 +57,7 @@ rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
|
||||
[features]
|
||||
deny-warnings = ["clippy_lints/deny-warnings"]
|
||||
integration = ["tempfile"]
|
||||
internal-lints = ["clippy_lints/internal-lints"]
|
||||
metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"]
|
||||
internal = ["clippy_lints/internal"]
|
||||
|
||||
[package.metadata.rust-analyzer]
|
||||
# This package uses #[feature(rustc_private)]
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
||||
|
||||
[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
[There are over 500 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
|
||||
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
|
||||
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
|
||||
@ -37,8 +37,8 @@ Table of contents:
|
||||
|
||||
## Usage
|
||||
|
||||
Below are instructions on how to use Clippy as a subcommand, compiled from source
|
||||
or in Travis CI.
|
||||
Below are instructions on how to use Clippy as a cargo subcommand,
|
||||
in projects that do not use cargo, or in Travis CI.
|
||||
|
||||
### As a cargo subcommand (`cargo clippy`)
|
||||
|
||||
@ -98,22 +98,18 @@ If you want to run Clippy **only** on the given crate, use the `--no-deps` optio
|
||||
cargo clippy -p example -- --no-deps
|
||||
```
|
||||
|
||||
### As a rustc replacement (`clippy-driver`)
|
||||
### Using `clippy-driver`
|
||||
|
||||
Clippy can also be used in projects that do not use cargo. To do so, you will need to replace
|
||||
your `rustc` compilation commands with `clippy-driver`. For example, if your project runs:
|
||||
|
||||
```terminal
|
||||
rustc --edition 2018 -Cpanic=abort foo.rs
|
||||
```
|
||||
|
||||
Then, to enable Clippy, you will need to call:
|
||||
Clippy can also be used in projects that do not use cargo. To do so, run `clippy-driver`
|
||||
with the same arguments you use for `rustc`. For example:
|
||||
|
||||
```terminal
|
||||
clippy-driver --edition 2018 -Cpanic=abort foo.rs
|
||||
```
|
||||
|
||||
Note that `rustc` will still run, i.e. it will still emit the output files it normally does.
|
||||
Note that `clippy-driver` is designed for running Clippy only and should not be used as a general
|
||||
replacement for `rustc`. `clippy-driver` may produce artifacts that are not optimized as expected,
|
||||
for example.
|
||||
|
||||
### Travis CI
|
||||
|
||||
|
@ -3,7 +3,7 @@ use itertools::Itertools;
|
||||
use shell_escape::escape;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::Path;
|
||||
use std::process::{self, Command};
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::{fs, io};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
@ -31,6 +31,7 @@ impl From<walkdir::Error> for CliError {
|
||||
struct FmtContext {
|
||||
check: bool,
|
||||
verbose: bool,
|
||||
rustfmt_path: String,
|
||||
}
|
||||
|
||||
// the "main" function of cargo dev fmt
|
||||
@ -102,7 +103,23 @@ Please revert the changes to Cargo.tomls first."
|
||||
}
|
||||
}
|
||||
|
||||
let context = FmtContext { check, verbose };
|
||||
let output = Command::new("rustup")
|
||||
.args(["which", "rustfmt"])
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.expect("error running `rustup which rustfmt`");
|
||||
if !output.status.success() {
|
||||
eprintln!("`rustup which rustfmt` did not execute successfully");
|
||||
process::exit(1);
|
||||
}
|
||||
let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path");
|
||||
rustfmt_path.truncate(rustfmt_path.trim_end().len());
|
||||
|
||||
let context = FmtContext {
|
||||
check,
|
||||
verbose,
|
||||
rustfmt_path,
|
||||
};
|
||||
let result = try_run(&context);
|
||||
let code = match result {
|
||||
Ok(true) => 0,
|
||||
@ -141,8 +158,12 @@ fn exec(
|
||||
println!("{}", format_command(&program, &dir, args));
|
||||
}
|
||||
|
||||
let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
|
||||
let output = child.wait_with_output()?;
|
||||
let output = Command::new(&program)
|
||||
.env("RUSTFMT", &context.rustfmt_path)
|
||||
.current_dir(&dir)
|
||||
.args(args.iter())
|
||||
.output()
|
||||
.unwrap();
|
||||
let success = output.status.success();
|
||||
|
||||
if !context.check && !success {
|
||||
@ -159,7 +180,6 @@ fn exec(
|
||||
fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
|
||||
let mut args = vec!["fmt", "--all"];
|
||||
if context.check {
|
||||
args.push("--");
|
||||
args.push("--check");
|
||||
}
|
||||
let success = exec(context, "cargo", path, &args)?;
|
||||
@ -200,7 +220,7 @@ fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Resul
|
||||
}
|
||||
args.extend(paths);
|
||||
|
||||
let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
|
||||
let success = exec(context, &context.rustfmt_path, std::env::current_dir()?, &args)?;
|
||||
|
||||
Ok(success)
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ fn gen_register_lint_list<'a>(
|
||||
|
||||
for (is_public, module_name, lint_name) in details {
|
||||
if !is_public {
|
||||
output.push_str(" #[cfg(feature = \"internal-lints\")]\n");
|
||||
output.push_str(" #[cfg(feature = \"internal\")]\n");
|
||||
}
|
||||
output.push_str(&format!(" {}::{},\n", module_name, lint_name));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
@ -30,8 +30,7 @@ url = { version = "2.2", features = ["serde"] }
|
||||
[features]
|
||||
deny-warnings = ["clippy_utils/deny-warnings"]
|
||||
# build clippy with internal lints enabled, off by default
|
||||
internal-lints = ["clippy_utils/internal-lints"]
|
||||
metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"]
|
||||
internal = ["clippy_utils/internal", "serde_json"]
|
||||
|
||||
[package.metadata.rust-analyzer]
|
||||
# This crate uses #[feature(rustc_private)]
|
||||
|
@ -1,12 +1,10 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -36,107 +34,39 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
let lint_true = |is_debug: bool| {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
|
||||
let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
|
||||
Some(sym::debug_assert_macro) => true,
|
||||
Some(sym::assert_macro) => false,
|
||||
_ => return,
|
||||
};
|
||||
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
|
||||
let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return };
|
||||
if val {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ASSERTIONS_ON_CONSTANTS,
|
||||
e.span,
|
||||
if is_debug {
|
||||
"`debug_assert!(true)` will be optimized out by the compiler"
|
||||
} else {
|
||||
"`assert!(true)` will be optimized out by the compiler"
|
||||
},
|
||||
macro_call.span,
|
||||
&format!(
|
||||
"`{}!(true)` will be optimized out by the compiler",
|
||||
cx.tcx.item_name(macro_call.def_id)
|
||||
),
|
||||
None,
|
||||
"remove it",
|
||||
);
|
||||
};
|
||||
let lint_false_without_message = || {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ASSERTIONS_ON_CONSTANTS,
|
||||
e.span,
|
||||
"`assert!(false)` should probably be replaced",
|
||||
None,
|
||||
"use `panic!()` or `unreachable!()`",
|
||||
);
|
||||
};
|
||||
let lint_false_with_message = |panic_message: String| {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ASSERTIONS_ON_CONSTANTS,
|
||||
e.span,
|
||||
&format!("`assert!(false, {})` should probably be replaced", panic_message),
|
||||
None,
|
||||
&format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
|
||||
);
|
||||
};
|
||||
|
||||
if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
|
||||
if debug_assert_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if_chain! {
|
||||
if let ExprKind::Unary(_, lit) = e.kind;
|
||||
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
|
||||
if is_true;
|
||||
then {
|
||||
lint_true(true);
|
||||
}
|
||||
} else if !is_debug {
|
||||
let (assert_arg, panic_arg) = match panic_expn {
|
||||
PanicExpn::Empty => ("", ""),
|
||||
_ => (", ..", ".."),
|
||||
};
|
||||
} else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") {
|
||||
if assert_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let Some(assert_match) = match_assert_with_message(cx, e) {
|
||||
match assert_match {
|
||||
// matched assert but not message
|
||||
AssertKind::WithoutMessage(false) => lint_false_without_message(),
|
||||
AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false),
|
||||
AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message),
|
||||
};
|
||||
}
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ASSERTIONS_ON_CONSTANTS,
|
||||
macro_call.span,
|
||||
&format!("`assert!(false{})` should probably be replaced", assert_arg),
|
||||
None,
|
||||
&format!("use `panic!({})` or `unreachable!({0})`", panic_arg),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of calling `match_assert_with_message`.
|
||||
enum AssertKind {
|
||||
WithMessage(String, bool),
|
||||
WithoutMessage(bool),
|
||||
}
|
||||
|
||||
/// Check if the expression matches
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// if !c {
|
||||
/// {
|
||||
/// ::std::rt::begin_panic(message, _)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// where `message` is any expression and `c` is a constant bool.
|
||||
fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
|
||||
if_chain! {
|
||||
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
|
||||
if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
|
||||
// bind the first argument of the `assert!` macro
|
||||
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
|
||||
let begin_panic_call = peel_blocks(then);
|
||||
// function call
|
||||
if let Some(arg) = match_panic_call(cx, begin_panic_call);
|
||||
// bind the second argument of the `assert!` macro if it exists
|
||||
if let panic_message = snippet_opt(cx, arg.span);
|
||||
// second argument of begin_panic is irrelevant
|
||||
// as is the second match arm
|
||||
then {
|
||||
// an empty message occurs when it was generated by the macro
|
||||
// (and not passed by the user)
|
||||
return panic_message
|
||||
.filter(|msg| !msg.is_empty())
|
||||
.map(|msg| AssertKind::WithMessage(msg, is_true))
|
||||
.or(Some(AssertKind::WithoutMessage(is_true)));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
//! checks for attributes
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::macros::{is_panic, macro_backtrace};
|
||||
use clippy_utils::msrvs;
|
||||
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
|
||||
use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv};
|
||||
use clippy_utils::{extract_msrv_attr, meets_msrv};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
|
||||
use rustc_errors::Applicability;
|
||||
@ -443,20 +444,15 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
|
||||
}
|
||||
|
||||
fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
|
||||
if macro_backtrace(expr.span).last().map_or(false, |macro_call| {
|
||||
is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
match &expr.kind {
|
||||
ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
|
||||
ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
|
||||
ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
|
||||
ExprKind::Call(path_expr, _) => {
|
||||
if let ExprKind::Path(qpath) = &path_expr.kind {
|
||||
typeck_results
|
||||
.qpath_res(qpath, path_expr.hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(true, |fun_id| !match_panic_def_id(cx, fun_id))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, is_direct_expn_of, ty::implements_trait};
|
||||
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Lit};
|
||||
@ -41,7 +42,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
|
||||
) && !e.span.from_expansion()
|
||||
}
|
||||
|
||||
fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
||||
fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(e);
|
||||
|
||||
cx.tcx
|
||||
@ -66,44 +67,40 @@ fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let macros = ["assert_eq", "debug_assert_eq"];
|
||||
let inverted_macros = ["assert_ne", "debug_assert_ne"];
|
||||
|
||||
for mac in macros.iter().chain(inverted_macros.iter()) {
|
||||
if let Some(span) = is_direct_expn_of(expr.span, mac) {
|
||||
if let Some(args) = higher::extract_assert_macro_args(expr) {
|
||||
if let [a, b, ..] = args[..] {
|
||||
let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b));
|
||||
|
||||
if nb_bool_args != 1 {
|
||||
// If there are two boolean arguments, we definitely don't understand
|
||||
// what's going on, so better leave things as is...
|
||||
//
|
||||
// Or there is simply no boolean and then we can leave things as is!
|
||||
return;
|
||||
}
|
||||
|
||||
if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
|
||||
// At this point the expression which is not a boolean
|
||||
// literal does not implement Not trait with a bool output,
|
||||
// so we cannot suggest to rewrite our code
|
||||
return;
|
||||
}
|
||||
|
||||
let non_eq_mac = &mac[..mac.len() - 3];
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
BOOL_ASSERT_COMPARISON,
|
||||
span,
|
||||
&format!("used `{}!` with a literal bool", mac),
|
||||
"replace it with",
|
||||
format!("{}!(..)", non_eq_mac),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let macro_name = cx.tcx.item_name(macro_call.def_id);
|
||||
if !matches!(
|
||||
macro_name.as_str(),
|
||||
"assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
|
||||
if !(is_bool_lit(a) ^ is_bool_lit(b)) {
|
||||
// If there are two boolean arguments, we definitely don't understand
|
||||
// what's going on, so better leave things as is...
|
||||
//
|
||||
// Or there is simply no boolean and then we can leave things as is!
|
||||
return;
|
||||
}
|
||||
|
||||
if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
|
||||
// At this point the expression which is not a boolean
|
||||
// literal does not implement Not trait with a bool output,
|
||||
// so we cannot suggest to rewrite our code
|
||||
return;
|
||||
}
|
||||
|
||||
let macro_name = macro_name.as_str();
|
||||
let non_eq_mac = ¯o_name[..macro_name.len() - 3];
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
BOOL_ASSERT_COMPARISON,
|
||||
macro_call.span,
|
||||
&format!("used `{}!` with a literal bool", macro_name),
|
||||
"replace it with",
|
||||
format!("{}!(..)", non_eq_mac),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
97
src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
Normal file
97
src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_no_std_crate;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for the usage of `&expr as *const T` or
|
||||
/// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
|
||||
/// `ptr::addr_of_mut` instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This would improve readability and avoid creating a reference
|
||||
/// that points to an uninitialized value or unaligned place.
|
||||
/// Read the `ptr::addr_of` docs for more information.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let val = 1;
|
||||
/// let p = &val as *const i32;
|
||||
///
|
||||
/// let mut val_mut = 1;
|
||||
/// let p_mut = &mut val_mut as *mut i32;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let val = 1;
|
||||
/// let p = std::ptr::addr_of!(val);
|
||||
///
|
||||
/// let mut val_mut = 1;
|
||||
/// let p_mut = std::ptr::addr_of_mut!(val_mut);
|
||||
/// ```
|
||||
#[clippy::version = "1.60.0"]
|
||||
pub BORROW_AS_PTR,
|
||||
pedantic,
|
||||
"borrowing just to cast to a raw pointer"
|
||||
}
|
||||
|
||||
impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
|
||||
|
||||
pub struct BorrowAsPtr {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl BorrowAsPtr {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) {
|
||||
return;
|
||||
}
|
||||
|
||||
if expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Cast(left_expr, ty) = &expr.kind;
|
||||
if let TyKind::Ptr(_) = ty.kind;
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
|
||||
|
||||
then {
|
||||
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
|
||||
let macro_name = match mutability {
|
||||
Mutability::Not => "addr_of",
|
||||
Mutability::Mut => "addr_of_mut",
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
BORROW_AS_PTR,
|
||||
expr.span,
|
||||
"borrow as raw pointer",
|
||||
"try",
|
||||
format!(
|
||||
"{}::ptr::{}!({})",
|
||||
core_or_std,
|
||||
macro_name,
|
||||
snippet_opt(cx, e.span).unwrap()
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
|
||||
None
|
||||
}
|
||||
|
||||
impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
|
||||
impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
|
||||
fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
|
||||
span_lint_and_help(
|
||||
|
@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
|
||||
|
||||
use super::CAST_PTR_ALIGNMENT;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
|
||||
if is_hir_ty_cfg_dependant(cx, cast_to) {
|
||||
return;
|
||||
|
@ -6,7 +6,7 @@ use rustc_middle::ty;
|
||||
|
||||
use super::CAST_REF_TO_MUT;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind;
|
||||
if let ExprKind::Cast(e, t) = &e.kind;
|
||||
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{self, UintTy};
|
||||
|
||||
use super::CHAR_LIT_AS_U8;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Cast(e, _) = &expr.kind;
|
||||
if let ExprKind::Lit(l) = &e.kind;
|
||||
|
@ -12,7 +12,7 @@ use rustc_semver::RustcVersion;
|
||||
|
||||
use super::PTR_AS_PTR;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option<RustcVersion>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
|
||||
if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
|
||||
return;
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ struct BlockEqual {
|
||||
|
||||
/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
|
||||
/// abort any further processing and avoid duplicate lint triggers.
|
||||
fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<BlockEqual> {
|
||||
fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<BlockEqual> {
|
||||
let mut start_eq = usize::MAX;
|
||||
let mut end_eq = usize::MAX;
|
||||
let mut expr_eq = true;
|
||||
@ -385,11 +385,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
|
||||
})
|
||||
}
|
||||
|
||||
fn check_for_warn_of_moved_symbol(
|
||||
cx: &LateContext<'tcx>,
|
||||
symbols: &FxHashSet<Symbol>,
|
||||
if_expr: &'tcx Expr<'_>,
|
||||
) -> bool {
|
||||
fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &FxHashSet<Symbol>, if_expr: &Expr<'_>) -> bool {
|
||||
get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| {
|
||||
let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
|
||||
|
||||
@ -419,13 +415,13 @@ fn check_for_warn_of_moved_symbol(
|
||||
}
|
||||
|
||||
fn emit_branches_sharing_code_lint(
|
||||
cx: &LateContext<'tcx>,
|
||||
cx: &LateContext<'_>,
|
||||
start_stmts: usize,
|
||||
end_stmts: usize,
|
||||
lint_end: bool,
|
||||
warn_about_moved_symbol: bool,
|
||||
blocks: &[&Block<'tcx>],
|
||||
if_expr: &'tcx Expr<'_>,
|
||||
blocks: &[&Block<'_>],
|
||||
if_expr: &Expr<'_>,
|
||||
) {
|
||||
if start_stmts == 0 && !lint_end {
|
||||
return;
|
||||
|
@ -77,7 +77,7 @@ pub struct Default {
|
||||
|
||||
impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
|
||||
|
||||
impl LateLintPass<'_> for Default {
|
||||
impl<'tcx> LateLintPass<'tcx> for Default {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion();
|
||||
@ -110,7 +110,7 @@ impl LateLintPass<'_> for Default {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
|
||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
|
||||
// start from the `let mut _ = _::default();` and look at all the following
|
||||
// statements, see if they re-assign the fields of the binding
|
||||
let stmts_head = match block.stmts {
|
||||
|
@ -54,7 +54,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
|
||||
|
||||
impl LateLintPass<'_> for DefaultNumericFallback {
|
||||
impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
|
||||
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
|
||||
let mut visitor = NumericFallbackVisitor::new(cx);
|
||||
visitor.visit_body(body);
|
||||
|
@ -355,7 +355,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_parse_ref_op(
|
||||
fn try_parse_ref_op<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typeck: &'tcx TypeckResults<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
@ -387,7 +387,7 @@ fn try_parse_ref_op(
|
||||
|
||||
// Checks whether the type for a deref call actually changed the type, not just the mutability of
|
||||
// the reference.
|
||||
fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
|
||||
fn deref_method_same_type(result_ty: Ty<'_>, arg_ty: Ty<'_>) -> bool {
|
||||
match (result_ty.kind(), arg_ty.kind()) {
|
||||
(ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty),
|
||||
|
||||
@ -457,7 +457,7 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
|
||||
}
|
||||
|
||||
/// Adjustments are sometimes made in the parent block rather than the expression itself.
|
||||
fn find_adjustments(
|
||||
fn find_adjustments<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typeck: &'tcx TypeckResults<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
@ -499,7 +499,7 @@ fn find_adjustments(
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
|
||||
fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) {
|
||||
match state {
|
||||
State::DerefMethod {
|
||||
ty_changed_count,
|
||||
@ -568,7 +568,7 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
|
||||
}
|
||||
|
||||
impl Dereferencing {
|
||||
fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
|
||||
fn check_local_usage(&mut self, cx: &LateContext<'_>, e: &Expr<'_>, local: HirId) {
|
||||
if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
|
||||
if let Some(pat) = outer_pat {
|
||||
// Check for auto-deref
|
||||
|
@ -11,6 +11,9 @@ declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Denies the configured methods and functions in clippy.toml
|
||||
///
|
||||
/// Note: Even though this lint is warn-by-default, it will only trigger if
|
||||
/// methods are defined in the clippy.toml file.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Some methods are undesirable in certain contexts, and it's beneficial to
|
||||
/// lint for them as needed.
|
||||
@ -49,14 +52,14 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
#[clippy::version = "1.49.0"]
|
||||
pub DISALLOWED_METHODS,
|
||||
nursery,
|
||||
style,
|
||||
"use of a disallowed method call"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedMethods {
|
||||
conf_disallowed: Vec<conf::DisallowedMethod>,
|
||||
disallowed: DefIdMap<Option<String>>,
|
||||
disallowed: DefIdMap<usize>,
|
||||
}
|
||||
|
||||
impl DisallowedMethods {
|
||||
@ -72,17 +75,10 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for conf in &self.conf_disallowed {
|
||||
let (path, reason) = match conf {
|
||||
conf::DisallowedMethod::Simple(path) => (path, None),
|
||||
conf::DisallowedMethod::WithReason { path, reason } => (
|
||||
path,
|
||||
reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
|
||||
),
|
||||
};
|
||||
let segs: Vec<_> = path.split("::").collect();
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
|
||||
self.disallowed.insert(id, reason);
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,15 +88,17 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
||||
Some(def_id) => def_id,
|
||||
None => return,
|
||||
};
|
||||
let reason = match self.disallowed.get(&def_id) {
|
||||
Some(reason) => reason,
|
||||
let conf = match self.disallowed.get(&def_id) {
|
||||
Some(&index) => &self.conf_disallowed[index],
|
||||
None => return,
|
||||
};
|
||||
let func_path = cx.tcx.def_path_str(def_id);
|
||||
let msg = format!("use of a disallowed method `{}`", func_path);
|
||||
let msg = format!("use of a disallowed method `{}`", conf.path());
|
||||
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
if let conf::DisallowedMethod::WithReason {
|
||||
reason: Some(reason), ..
|
||||
} = conf
|
||||
{
|
||||
diag.note(&format!("{} (from clippy.toml)", reason));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Denies the configured types in clippy.toml.
|
||||
///
|
||||
/// Note: Even though this lint is warn-by-default, it will only trigger if
|
||||
/// types are defined in the clippy.toml file.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Some types are undesirable in certain contexts.
|
||||
///
|
||||
@ -44,7 +47,7 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
#[clippy::version = "1.55.0"]
|
||||
pub DISALLOWED_TYPES,
|
||||
nursery,
|
||||
style,
|
||||
"use of disallowed types"
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1,8 +1,9 @@
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
|
||||
use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
|
||||
@ -13,7 +14,7 @@ use rustc_errors::emitter::EmitterWriter;
|
||||
use rustc_errors::{Applicability, Handler, SuggestionStyle};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
|
||||
use rustc_hir::{AnonConst, Expr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
@ -805,24 +806,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for `begin_panic`
|
||||
if_chain! {
|
||||
if let ExprKind::Call(func_expr, _) = expr.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
|
||||
if let Some(path_def_id) = path.res.opt_def_id();
|
||||
if match_panic_def_id(self.cx, path_def_id);
|
||||
if is_expn_of(expr.span, "unreachable").is_none();
|
||||
if !is_expn_of_debug_assertions(expr.span);
|
||||
then {
|
||||
self.panic_span = Some(expr.span);
|
||||
if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) {
|
||||
if is_panic(self.cx, macro_call.def_id)
|
||||
|| matches!(
|
||||
self.cx.tcx.item_name(macro_call.def_id).as_str(),
|
||||
"assert" | "assert_eq" | "assert_ne" | "todo"
|
||||
)
|
||||
{
|
||||
self.panic_span = Some(macro_call.span);
|
||||
}
|
||||
}
|
||||
|
||||
// check for `assert_eq` or `assert_ne`
|
||||
if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
|
||||
self.panic_span = Some(expr.span);
|
||||
}
|
||||
|
||||
// check for `unwrap`
|
||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
||||
@ -844,8 +838,3 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_expn_of_debug_assertions(span: Span) -> bool {
|
||||
const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
|
||||
MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ struct ContainsExpr<'tcx> {
|
||||
key: &'tcx Expr<'tcx>,
|
||||
call_ctxt: SyntaxContext,
|
||||
}
|
||||
fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
|
||||
fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
|
||||
let mut negated = false;
|
||||
let expr = peel_hir_expr_while(expr, |e| match e.kind {
|
||||
ExprKind::Unary(UnOp::Not, e) => {
|
||||
@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
|
||||
key: &'tcx Expr<'tcx>,
|
||||
value: &'tcx Expr<'tcx>,
|
||||
}
|
||||
fn try_parse_insert(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
|
||||
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
|
||||
if let ExprKind::MethodCall(_, _, [map, key, value], _) = expr.kind {
|
||||
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
|
||||
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
|
||||
@ -301,7 +301,7 @@ enum Edit<'tcx> {
|
||||
/// An insertion into the map.
|
||||
Insertion(Insertion<'tcx>),
|
||||
}
|
||||
impl Edit<'tcx> {
|
||||
impl<'tcx> Edit<'tcx> {
|
||||
fn as_insertion(self) -> Option<Insertion<'tcx>> {
|
||||
if let Self::Insertion(i) = self { Some(i) } else { None }
|
||||
}
|
||||
@ -532,7 +532,7 @@ struct InsertSearchResults<'tcx> {
|
||||
allow_insert_closure: bool,
|
||||
is_single_insert: bool,
|
||||
}
|
||||
impl InsertSearchResults<'tcx> {
|
||||
impl<'tcx> InsertSearchResults<'tcx> {
|
||||
fn as_single_insertion(&self) -> Option<Insertion<'tcx>> {
|
||||
self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap())
|
||||
}
|
||||
@ -633,7 +633,7 @@ impl InsertSearchResults<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_insert_calls(
|
||||
fn find_insert_calls<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
contains_expr: &ContainsExpr<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
|
@ -1,10 +1,11 @@
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
|
||||
use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function};
|
||||
use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -68,32 +69,26 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
|
||||
|
||||
const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"];
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for EqOp {
|
||||
#[allow(clippy::similar_names, clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Block(block, _) = e.kind {
|
||||
for stmt in block.stmts {
|
||||
for amn in &ASSERT_MACRO_NAMES {
|
||||
if_chain! {
|
||||
if is_expn_of(stmt.span, amn).is_some();
|
||||
if let StmtKind::Semi(matchexpr) = stmt.kind;
|
||||
if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr);
|
||||
if macro_args.len() == 2;
|
||||
let (lhs, rhs) = (macro_args[0], macro_args[1]);
|
||||
if eq_expr_value(cx, lhs, rhs);
|
||||
if !is_in_test_function(cx.tcx, e.hir_id);
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
EQ_OP,
|
||||
lhs.span.to(rhs.span),
|
||||
&format!("identical args used in this `{}!` macro call", amn),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if_chain! {
|
||||
if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
|
||||
let name = cx.tcx.item_name(macro_call.def_id);
|
||||
matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne")
|
||||
.then(|| (macro_call, name))
|
||||
});
|
||||
if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn);
|
||||
if eq_expr_value(cx, lhs, rhs);
|
||||
if macro_call.is_local();
|
||||
if !is_in_test_function(cx.tcx, e.hir_id);
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
EQ_OP,
|
||||
lhs.span.to(rhs.span),
|
||||
&format!("identical args used in this `{}!` macro call", macro_name),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let ExprKind::Binary(op, left, right) = e.kind {
|
||||
|
@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
|
||||
fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
|
||||
if let Some(def_id) = cx.tcx.lang_items().eq_trait() {
|
||||
implements_trait(cx, ty, def_id, &[other.into()])
|
||||
} else {
|
||||
|
@ -1,9 +1,11 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::same_type_and_consts;
|
||||
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TypeckResults;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -35,24 +37,40 @@ impl<'tcx> LateLintPass<'tcx> for ErasingOp {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::Binary(ref cmp, left, right) = e.kind {
|
||||
let tck = cx.typeck_results();
|
||||
match cmp.node {
|
||||
BinOpKind::Mul | BinOpKind::BitAnd => {
|
||||
check(cx, left, e.span);
|
||||
check(cx, right, e.span);
|
||||
check(cx, tck, left, right, e);
|
||||
check(cx, tck, right, left, e);
|
||||
},
|
||||
BinOpKind::Div => check(cx, left, e.span),
|
||||
BinOpKind::Div => check(cx, tck, left, right, e),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) {
|
||||
if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) {
|
||||
fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool {
|
||||
let input_ty = tck.expr_ty(input).peel_refs();
|
||||
let output_ty = tck.expr_ty(output).peel_refs();
|
||||
!same_type_and_consts(input_ty, output_ty)
|
||||
}
|
||||
|
||||
fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
tck: &TypeckResults<'tcx>,
|
||||
op: &Expr<'tcx>,
|
||||
other: &Expr<'tcx>,
|
||||
parent: &Expr<'tcx>,
|
||||
) {
|
||||
if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
|
||||
if different_types(tck, other, parent) {
|
||||
return;
|
||||
}
|
||||
span_lint(
|
||||
cx,
|
||||
ERASING_OP,
|
||||
span,
|
||||
parent.span,
|
||||
"this operation will always return zero. This is likely not the intended outcome",
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
|
||||
use if_chain::if_chain;
|
||||
@ -12,6 +13,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -113,6 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
||||
// A type param function ref like `T::f` is not 'static, however
|
||||
// it is if cast like `T::f as fn()`. This seems like a rustc bug.
|
||||
if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
|
||||
let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
|
||||
if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
|
||||
if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
|
||||
then {
|
||||
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
|
||||
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::higher::FormatArgsExpn;
|
||||
use clippy_utils::macros::FormatArgsExpn;
|
||||
use clippy_utils::{is_expn_of, match_function_call, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(format_args) = FormatArgsExpn::parse(write_arg);
|
||||
if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg);
|
||||
then {
|
||||
let calling_macro =
|
||||
// ordering is important here, since `writeln!` uses `write!` internally
|
||||
@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
||||
)
|
||||
};
|
||||
let msg = format!("use of `{}.unwrap()`", used);
|
||||
if let [write_output] = *format_args.format_string_symbols {
|
||||
if let [write_output] = *format_args.format_string_parts {
|
||||
let mut write_output = write_output.to_string();
|
||||
if write_output.ends_with('\n') {
|
||||
write_output.pop();
|
||||
|
@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
|
||||
|
||||
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath};
|
||||
use rustc_hir::{Expr, ImplItemKind};
|
||||
|
||||
struct FindPanicUnwrap<'a, 'tcx> {
|
||||
lcx: &'a LateContext<'tcx>,
|
||||
@ -80,14 +81,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
// check for `begin_panic`
|
||||
if_chain! {
|
||||
if let ExprKind::Call(func_expr, _) = expr.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
|
||||
if let Some(path_def_id) = path.res.opt_def_id();
|
||||
if match_panic_def_id(self.lcx, path_def_id);
|
||||
if is_expn_of(expr.span, "unreachable").is_none();
|
||||
then {
|
||||
if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
|
||||
if is_panic(self.lcx, macro_call.def_id) {
|
||||
self.result.push(expr.span);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher::FormatExpn;
|
||||
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
@ -43,38 +43,41 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) {
|
||||
Some(e) if !e.call_site.from_expansion() => e,
|
||||
_ => return,
|
||||
let (format_args, call_site) = if_chain! {
|
||||
if let Some(macro_call) = root_macro_call_first_node(cx, expr);
|
||||
if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id);
|
||||
if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn);
|
||||
then {
|
||||
(format_args, macro_call.span)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
};
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if format_args.value_args.is_empty() {
|
||||
if format_args.format_string_parts.is_empty() {
|
||||
span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
|
||||
} else {
|
||||
if_chain! {
|
||||
if let [e] = &*format_args.format_string_parts;
|
||||
if let ExprKind::Lit(lit) = &e.kind;
|
||||
if let Some(s_src) = snippet_opt(cx, lit.span);
|
||||
then {
|
||||
match *format_args.format_string_parts {
|
||||
[] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
|
||||
[_] => {
|
||||
if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
|
||||
// Simulate macro expansion, converting {{ and }} to { and }.
|
||||
let s_expand = s_src.replace("{{", "{").replace("}}", "}");
|
||||
let sugg = format!("{}.to_string()", s_expand);
|
||||
span_useless_format(cx, call_site, sugg, applicability);
|
||||
}
|
||||
}
|
||||
},
|
||||
[..] => {},
|
||||
}
|
||||
} else if let [value] = *format_args.value_args {
|
||||
if_chain! {
|
||||
if format_args.format_string_symbols == [kw::Empty];
|
||||
if format_args.format_string_parts == [kw::Empty];
|
||||
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
|
||||
ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
if let Some(args) = format_args.args();
|
||||
if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
|
||||
if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting());
|
||||
then {
|
||||
let is_new_string = match value.kind {
|
||||
ExprKind::Binary(..) => true,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
|
||||
use clippy_utils::macros::{FormatArgsArg, FormatArgsExpn};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_diag_trait_item, match_def_path, paths};
|
||||
@ -83,7 +83,7 @@ const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_m
|
||||
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if let Some(format_args) = FormatArgsExpn::parse(expr);
|
||||
if let Some(format_args) = FormatArgsExpn::parse(cx, expr);
|
||||
let expr_expn_data = expr.span.ctxt().outer_expn_data();
|
||||
let outermost_expn_data = outermost_expn_data(expr_expn_data);
|
||||
if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
|
||||
@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
||||
if let Some(args) = format_args.args();
|
||||
then {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if !arg.is_display() {
|
||||
if arg.format_trait != sym::Display {
|
||||
continue;
|
||||
}
|
||||
if arg.has_string_formatting() {
|
||||
@ -106,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
||||
if is_aliased(&args, i) {
|
||||
continue;
|
||||
}
|
||||
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
|
||||
check_to_string_in_format_args(cx, name, arg);
|
||||
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
|
||||
check_to_string_in_format_args(cx, name, arg.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,30 +122,31 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
|
||||
if_chain! {
|
||||
if FormatExpn::parse(arg.value).is_some();
|
||||
if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
|
||||
then {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
FORMAT_IN_FORMAT_ARGS,
|
||||
call_site,
|
||||
&format!("`format!` in `{}!` args", name),
|
||||
|diag| {
|
||||
diag.help(&format!(
|
||||
"combine the `format!(..)` arguments with the outer `{}!(..)` call",
|
||||
name
|
||||
));
|
||||
diag.help("or consider changing `format!` to `format_args!`");
|
||||
},
|
||||
);
|
||||
}
|
||||
fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
|
||||
let expn_data = arg.span.ctxt().outer_expn_data();
|
||||
if expn_data.call_site.from_expansion() {
|
||||
return;
|
||||
}
|
||||
let Some(mac_id) = expn_data.macro_def_id else { return };
|
||||
if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) {
|
||||
return;
|
||||
}
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
FORMAT_IN_FORMAT_ARGS,
|
||||
call_site,
|
||||
&format!("`format!` in `{}!` args", name),
|
||||
|diag| {
|
||||
diag.help(&format!(
|
||||
"combine the `format!(..)` arguments with the outer `{}!(..)` call",
|
||||
name
|
||||
));
|
||||
diag.help("or consider changing `format!` to `format_args!`");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
|
||||
let value = arg.value;
|
||||
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if !value.span.from_expansion();
|
||||
if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
|
||||
|
@ -53,7 +53,7 @@ impl FromOverInto {
|
||||
|
||||
impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
|
||||
|
||||
impl LateLintPass<'_> for FromOverInto {
|
||||
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) {
|
||||
return;
|
||||
|
@ -43,7 +43,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
|
||||
|
||||
impl LateLintPass<'tcx> for FromStrRadix10 {
|
||||
impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
|
||||
|
@ -18,7 +18,7 @@ use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method
|
||||
|
||||
use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
|
||||
|
||||
pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let attr = must_use_attr(attrs);
|
||||
if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
|
||||
@ -40,7 +40,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
|
||||
pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
|
||||
if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
|
||||
let is_public = cx.access_levels.is_exported(item.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
@ -62,7 +62,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
|
||||
let is_public = cx.access_levels.is_exported(item.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
|
@ -9,7 +9,7 @@ use clippy_utils::{iter_input_pats, path_to_local};
|
||||
|
||||
use super::NOT_UNSAFE_PTR_ARG_DEREF;
|
||||
|
||||
pub(super) fn check_fn(
|
||||
pub(super) fn check_fn<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
kind: intravisit::FnKind<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
@ -25,14 +25,14 @@ pub(super) fn check_fn(
|
||||
check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_raw_ptr(
|
||||
fn check_raw_ptr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
unsafety: hir::Unsafety,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
|
@ -13,7 +13,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
|
||||
|
||||
use super::RESULT_UNIT_ERR;
|
||||
|
||||
pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
|
||||
let is_public = cx.access_levels.is_exported(item.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
@ -23,7 +23,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
|
||||
pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
|
||||
if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
|
||||
let is_public = cx.access_levels.is_exported(item.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
@ -33,7 +33,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
|
||||
let is_public = cx.access_levels.is_exported(item.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
|
@ -9,9 +9,9 @@ use clippy_utils::is_trait_impl_item;
|
||||
use super::TOO_MANY_ARGUMENTS;
|
||||
|
||||
pub(super) fn check_fn(
|
||||
cx: &LateContext<'tcx>,
|
||||
kind: intravisit::FnKind<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'_>,
|
||||
cx: &LateContext<'_>,
|
||||
kind: intravisit::FnKind<'_>,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
span: Span,
|
||||
hir_id: hir::HirId,
|
||||
too_many_arguments_threshold: u64,
|
||||
@ -39,11 +39,7 @@ pub(super) fn check_fn(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item(
|
||||
cx: &LateContext<'tcx>,
|
||||
item: &'tcx hir::TraitItem<'_>,
|
||||
too_many_arguments_threshold: u64,
|
||||
) {
|
||||
pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
|
||||
// don't lint extern functions decls, it's not their fault
|
||||
if sig.header.abi == Abi::Rust {
|
||||
|
@ -11,9 +11,9 @@ use super::TOO_MANY_LINES;
|
||||
|
||||
pub(super) fn check_fn(
|
||||
cx: &LateContext<'_>,
|
||||
kind: FnKind<'tcx>,
|
||||
kind: FnKind<'_>,
|
||||
span: Span,
|
||||
body: &'tcx hir::Body<'_>,
|
||||
body: &hir::Body<'_>,
|
||||
too_many_lines_threshold: u64,
|
||||
) {
|
||||
// Closures must be contained in a parent body, which will be checked for `too_many_lines`.
|
||||
|
@ -55,7 +55,7 @@ impl IfThenSomeElseNone {
|
||||
|
||||
impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
|
||||
|
||||
impl LateLintPass<'_> for IfThenSomeElseNone {
|
||||
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) {
|
||||
return;
|
||||
|
@ -94,8 +94,8 @@ fn get_call_site(span: Span, ctxt: SyntaxContext) -> Option<Span> {
|
||||
}
|
||||
|
||||
fn lint_implicit_returns(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
// The context of the function body.
|
||||
ctxt: SyntaxContext,
|
||||
// Whether the expression is from a macro expansion.
|
||||
|
@ -63,7 +63,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
|
||||
|
||||
impl LateLintPass<'_> for InconsistentStructConstructor {
|
||||
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion();
|
||||
|
@ -69,7 +69,7 @@ impl IndexRefutableSlice {
|
||||
|
||||
impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
|
||||
|
||||
impl LateLintPass<'_> for IndexRefutableSlice {
|
||||
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::in_macro;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -46,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Struct(path, fields, None) = e.kind {
|
||||
if !fields.is_empty()
|
||||
&& !in_macro(e.span)
|
||||
&& !e.span.from_expansion()
|
||||
&& fields
|
||||
.iter()
|
||||
.all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
|
||||
|
@ -1,8 +1,7 @@
|
||||
use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
|
||||
use rustc_hir::{ImplItem, ImplItemKind};
|
||||
use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
|
||||
use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -40,26 +39,52 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
|
||||
|
||||
impl LateLintPass<'_> for IterNotReturningIterator {
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
|
||||
let name = impl_item.ident.name.as_str();
|
||||
if_chain! {
|
||||
if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
|
||||
let ret_ty = return_ty(cx, impl_item.hir_id());
|
||||
if matches!(name, "iter" | "iter_mut");
|
||||
if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
|
||||
if param.name == kw::SelfLower;
|
||||
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
|
||||
impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
|
||||
let name = item.ident.name.as_str();
|
||||
if matches!(name, "iter" | "iter_mut") {
|
||||
if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
|
||||
check_sig(cx, name, fn_sig, item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
ITER_NOT_RETURNING_ITERATOR,
|
||||
fn_sig.span,
|
||||
&format!("this method is named `{}` but its return type does not implement `Iterator`", name),
|
||||
);
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
|
||||
let name = item.ident.name.as_str();
|
||||
if matches!(name, "iter" | "iter_mut")
|
||||
&& !matches!(
|
||||
get_parent_node(cx.tcx, item.hir_id()),
|
||||
Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some()
|
||||
)
|
||||
{
|
||||
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
|
||||
check_sig(cx, name, fn_sig, item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
|
||||
if sig.decl.implicit_self.has_implicit_self() {
|
||||
let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
|
||||
let ret_ty = cx
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(cx.param_env, ret_ty)
|
||||
.unwrap_or(ret_ty);
|
||||
if cx
|
||||
.tcx
|
||||
.get_diagnostic_item(sym::Iterator)
|
||||
.map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
ITER_NOT_RETURNING_ITERATOR,
|
||||
sig.span,
|
||||
&format!(
|
||||
"this method is named `{}` but its return type does not implement `Iterator`",
|
||||
name
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ enum LenOutput<'tcx> {
|
||||
Option(DefId),
|
||||
Result(DefId, Ty<'tcx>),
|
||||
}
|
||||
fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
|
||||
fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
|
||||
match *sig.output().kind() {
|
||||
ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
|
||||
ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
|
||||
|
@ -37,6 +37,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(derivable_impls::DERIVABLE_IMPLS),
|
||||
LintId::of(derive::DERIVE_HASH_XOR_EQ),
|
||||
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
|
||||
LintId::of(disallowed_methods::DISALLOWED_METHODS),
|
||||
LintId::of(disallowed_types::DISALLOWED_TYPES),
|
||||
LintId::of(doc::MISSING_SAFETY_DOC),
|
||||
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
|
||||
LintId::of(double_comparison::DOUBLE_COMPARISONS),
|
||||
@ -113,6 +115,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(loops::WHILE_LET_ON_ITERATOR),
|
||||
LintId::of(main_recursion::MAIN_RECURSION),
|
||||
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
|
||||
LintId::of(manual_bits::MANUAL_BITS),
|
||||
LintId::of(manual_map::MANUAL_MAP),
|
||||
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||
LintId::of(manual_strip::MANUAL_STRIP),
|
||||
@ -204,7 +207,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(mut_key::MUTABLE_KEY_TYPE),
|
||||
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
|
||||
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
|
||||
LintId::of(mutex_atomic::MUTEX_ATOMIC),
|
||||
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
|
||||
LintId::of(needless_bool::BOOL_COMPARISON),
|
||||
LintId::of(needless_bool::NEEDLESS_BOOL),
|
||||
|
@ -3,33 +3,33 @@
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_lints(&[
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::CLIPPY_LINTS_INTERNAL,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::COMPILER_LINT_FUNCTIONS,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::DEFAULT_LINT,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::IF_CHAIN_STYLE,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::INTERNING_DEFINED_SYMBOL,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::INVALID_PATHS,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::OUTER_EXPN_EXPN_DATA,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::PRODUCE_ICE,
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::UNNECESSARY_SYMBOL_STR,
|
||||
absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
|
||||
approx_const::APPROX_CONSTANT,
|
||||
@ -59,6 +59,7 @@ store.register_lints(&[
|
||||
bool_assert_comparison::BOOL_ASSERT_COMPARISON,
|
||||
booleans::LOGIC_BUG,
|
||||
booleans::NONMINIMAL_BOOL,
|
||||
borrow_as_ptr::BORROW_AS_PTR,
|
||||
bytecount::NAIVE_BYTECOUNT,
|
||||
cargo_common_metadata::CARGO_COMMON_METADATA,
|
||||
case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
|
||||
@ -225,6 +226,7 @@ store.register_lints(&[
|
||||
main_recursion::MAIN_RECURSION,
|
||||
manual_assert::MANUAL_ASSERT,
|
||||
manual_async_fn::MANUAL_ASYNC_FN,
|
||||
manual_bits::MANUAL_BITS,
|
||||
manual_map::MANUAL_MAP,
|
||||
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
|
||||
manual_ok_or::MANUAL_OK_OR,
|
||||
@ -435,6 +437,7 @@ store.register_lints(&[
|
||||
shadow::SHADOW_REUSE,
|
||||
shadow::SHADOW_SAME,
|
||||
shadow::SHADOW_UNRELATED,
|
||||
single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
|
||||
single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
|
||||
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
|
||||
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
|
||||
|
@ -6,8 +6,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
|
||||
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
|
||||
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
|
||||
LintId::of(copies::BRANCHES_SHARING_CODE),
|
||||
LintId::of(disallowed_methods::DISALLOWED_METHODS),
|
||||
LintId::of(disallowed_types::DISALLOWED_TYPES),
|
||||
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
|
||||
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
|
||||
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
|
||||
@ -17,6 +15,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
|
||||
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
|
||||
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
|
||||
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
|
||||
LintId::of(mutex_atomic::MUTEX_ATOMIC),
|
||||
LintId::of(mutex_atomic::MUTEX_INTEGER),
|
||||
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
|
||||
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
|
||||
|
@ -7,6 +7,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(bit_mask::VERBOSE_BIT_MASK),
|
||||
LintId::of(borrow_as_ptr::BORROW_AS_PTR),
|
||||
LintId::of(bytecount::NAIVE_BYTECOUNT),
|
||||
LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
|
||||
LintId::of(casts::CAST_LOSSLESS),
|
||||
|
@ -19,7 +19,6 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
|
||||
LintId::of(methods::SINGLE_CHAR_PATTERN),
|
||||
LintId::of(methods::UNNECESSARY_TO_OWNED),
|
||||
LintId::of(misc::CMP_OWNED),
|
||||
LintId::of(mutex_atomic::MUTEX_ATOMIC),
|
||||
LintId::of(redundant_clone::REDUNDANT_CLONE),
|
||||
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
|
||||
|
@ -54,6 +54,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
|
||||
LintId::of(shadow::SHADOW_REUSE),
|
||||
LintId::of(shadow::SHADOW_SAME),
|
||||
LintId::of(shadow::SHADOW_UNRELATED),
|
||||
LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
|
||||
LintId::of(strings::STRING_ADD),
|
||||
LintId::of(strings::STRING_SLICE),
|
||||
LintId::of(strings::STRING_TO_STRING),
|
||||
|
@ -16,6 +16,8 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
||||
LintId::of(comparison_chain::COMPARISON_CHAIN),
|
||||
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
|
||||
LintId::of(dereference::NEEDLESS_BORROW),
|
||||
LintId::of(disallowed_methods::DISALLOWED_METHODS),
|
||||
LintId::of(disallowed_types::DISALLOWED_TYPES),
|
||||
LintId::of(doc::MISSING_SAFETY_DOC),
|
||||
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
|
||||
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
|
||||
@ -41,6 +43,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
||||
LintId::of(loops::WHILE_LET_ON_ITERATOR),
|
||||
LintId::of(main_recursion::MAIN_RECURSION),
|
||||
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
|
||||
LintId::of(manual_bits::MANUAL_BITS),
|
||||
LintId::of(manual_map::MANUAL_MAP),
|
||||
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||
LintId::of(map_clone::MAP_CLONE),
|
||||
|
@ -4,7 +4,6 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_else)]
|
||||
#![feature(once_cell)]
|
||||
@ -153,12 +152,9 @@ macro_rules! declare_clippy_lint {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "metadata-collector-lint")]
|
||||
#[cfg(feature = "internal")]
|
||||
mod deprecated_lints;
|
||||
#[cfg_attr(
|
||||
any(feature = "internal-lints", feature = "metadata-collector-lint"),
|
||||
allow(clippy::missing_clippy_version_attribute)
|
||||
)]
|
||||
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
||||
mod utils;
|
||||
|
||||
// begin lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
@ -177,6 +173,7 @@ mod blacklisted_name;
|
||||
mod blocks_in_if_conditions;
|
||||
mod bool_assert_comparison;
|
||||
mod booleans;
|
||||
mod borrow_as_ptr;
|
||||
mod bytecount;
|
||||
mod cargo_common_metadata;
|
||||
mod case_sensitive_file_extension_comparisons;
|
||||
@ -264,6 +261,7 @@ mod macro_use;
|
||||
mod main_recursion;
|
||||
mod manual_assert;
|
||||
mod manual_async_fn;
|
||||
mod manual_bits;
|
||||
mod manual_map;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_ok_or;
|
||||
@ -351,6 +349,7 @@ mod self_named_constructors;
|
||||
mod semicolon_if_nothing_returned;
|
||||
mod serde_api;
|
||||
mod shadow;
|
||||
mod single_char_lifetime_names;
|
||||
mod single_component_path_imports;
|
||||
mod size_of_in_element_count;
|
||||
mod slow_vector_initialization;
|
||||
@ -471,7 +470,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
include!("lib.register_restriction.rs");
|
||||
include!("lib.register_pedantic.rs");
|
||||
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
include!("lib.register_internal.rs");
|
||||
|
||||
include!("lib.register_all.rs");
|
||||
@ -483,7 +482,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
include!("lib.register_cargo.rs");
|
||||
include!("lib.register_nursery.rs");
|
||||
|
||||
#[cfg(feature = "metadata-collector-lint")]
|
||||
#[cfg(feature = "internal")]
|
||||
{
|
||||
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
|
||||
store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
|
||||
@ -492,7 +491,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
}
|
||||
|
||||
// all the internal lints
|
||||
#[cfg(feature = "internal-lints")]
|
||||
#[cfg(feature = "internal")]
|
||||
{
|
||||
store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
|
||||
store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
|
||||
@ -858,6 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
|
||||
store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
|
||||
store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
|
||||
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
|
||||
store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
|
||||
store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::{is_in_panic_handler, is_no_std_crate};
|
||||
use rustc_hir::{Block, Expr};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_>) {
|
||||
if loop_block.stmts.is_empty() && loop_block.expr.is_none() && !is_in_panic_handler(cx, expr) {
|
||||
let msg = "empty `loop {}` wastes CPU cycles";
|
||||
let help = if is_no_std_crate(cx) {
|
||||
|
@ -8,7 +8,7 @@ use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::TyS;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
|
||||
let self_ty = cx.typeck_results().expr_ty(self_arg);
|
||||
let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
|
||||
if !(TyS::same_type(self_ty, self_ty_adjusted) && is_trait_method(cx, call_expr, sym::IntoIterator)) {
|
||||
|
@ -2,7 +2,7 @@ use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
@ -62,15 +62,15 @@ pub(super) fn check<'tcx>(
|
||||
if_chain! {
|
||||
if let ExprKind::Index(base_left, idx_left) = lhs.kind;
|
||||
if let ExprKind::Index(base_right, idx_right) = rhs.kind;
|
||||
if is_slice_like(cx, cx.typeck_results().expr_ty(base_left));
|
||||
if is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
|
||||
if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left));
|
||||
if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some();
|
||||
if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
|
||||
if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
|
||||
|
||||
// Source and destination must be different
|
||||
if path_to_local(base_left) != path_to_local(base_right);
|
||||
then {
|
||||
Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
|
||||
Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
|
||||
IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
|
||||
} else {
|
||||
None
|
||||
@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
|
||||
}
|
||||
})
|
||||
})
|
||||
.map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, &dst, &src)))
|
||||
.map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src)))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| v.join("\n "));
|
||||
@ -105,6 +105,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
||||
start: &Expr<'_>,
|
||||
end: &Expr<'_>,
|
||||
limits: ast::RangeLimits,
|
||||
elem_ty: Ty<'tcx>,
|
||||
dst: &IndexExpr<'_>,
|
||||
src: &IndexExpr<'_>,
|
||||
) -> String {
|
||||
@ -187,9 +188,16 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
||||
.into()
|
||||
};
|
||||
|
||||
let method_str = if is_copy(cx, elem_ty) {
|
||||
"copy_from_slice"
|
||||
} else {
|
||||
"clone_from_slice"
|
||||
};
|
||||
|
||||
format!(
|
||||
"{}.clone_from_slice(&{}[{}..{}]);",
|
||||
"{}.{}(&{}[{}..{}]);",
|
||||
dst,
|
||||
method_str,
|
||||
src_base_str,
|
||||
src_offset.maybe_par(),
|
||||
src_limit.maybe_par()
|
||||
@ -203,7 +211,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
||||
#[derive(Clone)]
|
||||
struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl Display for MinifyingSugg<'a> {
|
||||
impl<'a> Display for MinifyingSugg<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
@ -324,14 +332,13 @@ struct Start<'hir> {
|
||||
kind: StartKind<'hir>,
|
||||
}
|
||||
|
||||
fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
|
||||
let is_slice = match ty.kind() {
|
||||
ty::Ref(_, subty, _) => is_slice_like(cx, subty),
|
||||
ty::Slice(..) | ty::Array(..) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
is_slice || is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::VecDeque)
|
||||
fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
match ty.kind() {
|
||||
ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)),
|
||||
ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, subty),
|
||||
ty::Slice(ty) | ty::Array(ty, _) => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
||||
|
@ -147,7 +147,7 @@ impl BreakAfterExprVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
|
@ -339,8 +339,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_captured_ids(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>) -> HirIdSet {
|
||||
fn get_captured_ids_recursive(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
|
||||
fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet {
|
||||
fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
|
||||
match ty.kind() {
|
||||
ty::Adt(_, generics) => {
|
||||
for generic in *generics {
|
||||
|
@ -10,8 +10,8 @@ use rustc_span::Span;
|
||||
use std::iter::{once, Iterator};
|
||||
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'tcx>,
|
||||
block: &'tcx Block<'_>,
|
||||
cx: &LateContext<'_>,
|
||||
block: &Block<'_>,
|
||||
loop_id: HirId,
|
||||
span: Span,
|
||||
for_loop: Option<&ForLoop<'_>>,
|
||||
|
@ -7,7 +7,7 @@ use rustc_hir::{Block, Expr, ExprKind, MatchSource, Pat, StmtKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
||||
// extract the expression from the first statement (if any) in a block
|
||||
let inner_stmt_expr = extract_expr_from_first_stmt(loop_block);
|
||||
// or extract the first expression (if any) from the block
|
||||
|
@ -8,12 +8,13 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::{symbol::sym, Symbol};
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! {
|
||||
if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr);
|
||||
// check for `Some(..)` pattern
|
||||
if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind;
|
||||
@ -27,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// get the loop containing the match expression
|
||||
if !uses_iter(cx, &iter_expr_struct, if_then);
|
||||
then {
|
||||
(let_expr, iter_expr_struct, some_pat, expr)
|
||||
(let_expr, iter_expr_struct, iter_expr, some_pat, expr)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -47,7 +48,11 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let by_ref = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
|
||||
let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
|
||||
|| !iter_expr_struct.can_move
|
||||
|| !iter_expr_struct.fields.is_empty()
|
||||
|| needs_mutable_borrow(cx, &iter_expr_struct, loop_expr)
|
||||
{
|
||||
".by_ref()"
|
||||
} else {
|
||||
""
|
||||
@ -67,26 +72,36 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IterExpr {
|
||||
/// The span of the whole expression, not just the path and fields stored here.
|
||||
span: Span,
|
||||
/// The fields used, in order of child to parent.
|
||||
fields: Vec<Symbol>,
|
||||
/// The path being used.
|
||||
path: Res,
|
||||
/// Whether or not the iterator can be moved.
|
||||
can_move: bool,
|
||||
}
|
||||
|
||||
/// Parses any expression to find out which field of which variable is used. Will return `None` if
|
||||
/// the expression might have side effects.
|
||||
fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
|
||||
let span = e.span;
|
||||
let mut fields = Vec::new();
|
||||
let mut can_move = true;
|
||||
loop {
|
||||
if cx
|
||||
.typeck_results()
|
||||
.expr_adjustments(e)
|
||||
.iter()
|
||||
.any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
|
||||
{
|
||||
// Custom deref impls need to borrow the whole value as it's captured by reference
|
||||
can_move = false;
|
||||
fields.clear();
|
||||
}
|
||||
match e.kind {
|
||||
ExprKind::Path(ref path) => {
|
||||
break Some(IterExpr {
|
||||
span,
|
||||
fields,
|
||||
path: cx.qpath_res(path, e.hir_id),
|
||||
can_move,
|
||||
});
|
||||
},
|
||||
ExprKind::Field(base, name) => {
|
||||
@ -99,10 +114,12 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExp
|
||||
// Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
|
||||
// already been seen.
|
||||
ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
|
||||
can_move = false;
|
||||
fields.clear();
|
||||
e = base;
|
||||
},
|
||||
ExprKind::Unary(UnOp::Deref, base) => {
|
||||
can_move = false;
|
||||
fields.clear();
|
||||
e = base;
|
||||
},
|
||||
@ -174,7 +191,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie
|
||||
|
||||
/// Strips off all field and path expressions. This will return true if a field or path has been
|
||||
/// skipped. Used to skip them after failing to check for equality.
|
||||
fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
|
||||
fn skip_fields_and_path<'tcx>(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
|
||||
let mut e = expr;
|
||||
let e = loop {
|
||||
match e.kind {
|
||||
@ -187,13 +204,13 @@ fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool
|
||||
}
|
||||
|
||||
/// Checks if the given expression uses the iterator.
|
||||
fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
|
||||
fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
|
||||
struct V<'a, 'b, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
iter_expr: &'b IterExpr,
|
||||
uses_iter: bool,
|
||||
}
|
||||
impl Visitor<'tcx> for V<'_, '_, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
|
||||
type Map = ErasedMap<'tcx>;
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::None
|
||||
@ -228,7 +245,7 @@ fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool {
|
||||
fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
|
||||
struct AfterLoopVisitor<'a, 'b, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
iter_expr: &'b IterExpr,
|
||||
@ -236,7 +253,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
|
||||
after_loop: bool,
|
||||
used_iter: bool,
|
||||
}
|
||||
impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
|
||||
type Map = ErasedMap<'tcx>;
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::None
|
||||
@ -275,7 +292,7 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
|
||||
found_local: bool,
|
||||
used_after: bool,
|
||||
}
|
||||
impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
|
||||
type Map = ErasedMap<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::in_macro;
|
||||
use clippy_utils::source::snippet;
|
||||
use hir::def::{DefKind, Res};
|
||||
use if_chain::if_chain;
|
||||
@ -104,34 +103,34 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if in_macro(item.span) {
|
||||
if item.span.from_expansion() {
|
||||
self.push_unique_macro_pat_ty(cx, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
if in_macro(attr.span) {
|
||||
if attr.span.from_expansion() {
|
||||
self.push_unique_macro(cx, attr.span);
|
||||
}
|
||||
}
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
|
||||
if in_macro(expr.span) {
|
||||
if expr.span.from_expansion() {
|
||||
self.push_unique_macro(cx, expr.span);
|
||||
}
|
||||
}
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
|
||||
if in_macro(stmt.span) {
|
||||
if stmt.span.from_expansion() {
|
||||
self.push_unique_macro(cx, stmt.span);
|
||||
}
|
||||
}
|
||||
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
|
||||
if in_macro(pat.span) {
|
||||
if pat.span.from_expansion() {
|
||||
self.push_unique_macro_pat_ty(cx, pat.span);
|
||||
}
|
||||
}
|
||||
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
|
||||
if in_macro(ty.span) {
|
||||
if ty.span.from_expansion() {
|
||||
self.push_unique_macro_pat_ty(cx, ty.span);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher::PanicExpn;
|
||||
use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_expn_of, sugg};
|
||||
use clippy_utils::{peel_blocks_with_stmt, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -34,65 +35,34 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
|
||||
|
||||
impl LateLintPass<'_> for ManualAssert {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualAssert {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if let Expr {
|
||||
kind: ExprKind:: If(cond, Expr {
|
||||
kind: ExprKind::Block(
|
||||
Block {
|
||||
stmts: [stmt],
|
||||
..
|
||||
},
|
||||
_),
|
||||
..
|
||||
}, None),
|
||||
..
|
||||
} = &expr;
|
||||
if is_expn_of(stmt.span, "panic").is_some();
|
||||
if let ExprKind::If(cond, then, None) = expr.kind;
|
||||
if !matches!(cond.kind, ExprKind::Let(_));
|
||||
if let StmtKind::Semi(semi) = stmt.kind;
|
||||
if !expr.span.from_expansion();
|
||||
let then = peel_blocks_with_stmt(then);
|
||||
if let Some(macro_call) = root_macro_call(then.span);
|
||||
if cx.tcx.item_name(macro_call.def_id) == sym::panic;
|
||||
if !cx.tcx.sess.source_map().is_multiline(cond.span);
|
||||
|
||||
if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
|
||||
then {
|
||||
let call = if_chain! {
|
||||
if let ExprKind::Block(block, _) = semi.kind;
|
||||
if let Some(init) = block.expr;
|
||||
then {
|
||||
init
|
||||
} else {
|
||||
semi
|
||||
}
|
||||
};
|
||||
let span = if let Some(panic_expn) = PanicExpn::parse(call) {
|
||||
match *panic_expn.format_args.value_args {
|
||||
[] => panic_expn.format_args.format_string_span,
|
||||
[.., last] => panic_expn.format_args.format_string_span.to(last.span),
|
||||
}
|
||||
} else if let ExprKind::Call(_, [format_args]) = call.kind {
|
||||
format_args.span
|
||||
} else {
|
||||
return
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
|
||||
if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
|
||||
sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
|
||||
} else {
|
||||
format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
|
||||
}
|
||||
} else {
|
||||
format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
|
||||
let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
|
||||
let cond = cond.peel_drop_temps();
|
||||
let (cond, not) = match cond.kind {
|
||||
ExprKind::Unary(UnOp::Not, e) => (e, ""),
|
||||
_ => (cond, "!"),
|
||||
};
|
||||
|
||||
let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
|
||||
let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_ASSERT,
|
||||
expr.span,
|
||||
"only a `panic!` in `if`-then statement",
|
||||
"try",
|
||||
format!("assert!({}, {});", cond_sugg, sugg),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
107
src/tools/clippy/clippy_lints/src/manual_bits.rs
Normal file
107
src/tools/clippy/clippy_lints/src/manual_bits.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for uses of `std::mem::size_of::<T>() * 8` when
|
||||
/// `T::BITS` is available.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Can be written as the shorter `T::BITS`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// std::mem::size_of::<usize>() * 8;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// usize::BITS;
|
||||
/// ```
|
||||
#[clippy::version = "1.60.0"]
|
||||
pub MANUAL_BITS,
|
||||
style,
|
||||
"manual implementation of `size_of::<T>() * 8` can be simplified with `T::BITS`"
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ManualBits {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl ManualBits {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualBits => [MANUAL_BITS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualBits {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind;
|
||||
if let BinOpKind::Mul = &bin_op.node;
|
||||
if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr);
|
||||
if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
|
||||
if let ExprKind::Lit(lit) = &other_expr.kind;
|
||||
if let LitKind::Int(8, _) = lit.node;
|
||||
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_BITS,
|
||||
expr.span,
|
||||
"usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
|
||||
"consider using",
|
||||
format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_one_size_of_ty<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr1: &'tcx Expr<'_>,
|
||||
expr2: &'tcx Expr<'_>,
|
||||
) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
match (get_size_of_ty(cx, expr1), get_size_of_ty(cx, expr2)) {
|
||||
(Some((real_ty, resolved_ty)), None) => Some((real_ty, resolved_ty, expr2)),
|
||||
(None, Some((real_ty, resolved_ty))) => Some((real_ty, resolved_ty, expr1)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(count_func, _func_args) = expr.kind;
|
||||
if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
|
||||
|
||||
if let QPath::Resolved(_, count_func_path) = count_func_qpath;
|
||||
if let Some(segment_zero) = count_func_path.segments.get(0);
|
||||
if let Some(args) = segment_zero.args;
|
||||
if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
|
||||
|
||||
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
|
||||
if match_def_path(cx, def_id, &paths::MEM_SIZE_OF);
|
||||
then {
|
||||
cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(ManualMap => [MANUAL_MAP]);
|
||||
|
||||
impl LateLintPass<'_> for ManualMap {
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualMap {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
|
||||
@ -219,7 +219,7 @@ impl LateLintPass<'_> for ManualMap {
|
||||
|
||||
// Checks whether the expression could be passed as a function, or whether a closure is needed.
|
||||
// Returns the function to be passed to `map` if it exists.
|
||||
fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
match expr.kind {
|
||||
ExprKind::Call(func, [arg])
|
||||
if path_to_local_id(arg, binding)
|
||||
@ -251,8 +251,13 @@ struct SomeExpr<'tcx> {
|
||||
|
||||
// Try to parse into a recognized `Option` pattern.
|
||||
// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
|
||||
fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
|
||||
fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
|
||||
fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
|
||||
fn f<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat: &'tcx Pat<'_>,
|
||||
ref_count: usize,
|
||||
ctxt: SyntaxContext,
|
||||
) -> Option<OptionPat<'tcx>> {
|
||||
match pat.kind {
|
||||
PatKind::Wild => Some(OptionPat::Wild),
|
||||
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
@ -269,7 +274,7 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon
|
||||
}
|
||||
|
||||
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
|
||||
fn get_some_expr(
|
||||
fn get_some_expr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
needs_unsafe_block: bool,
|
||||
@ -306,6 +311,6 @@ fn get_some_expr(
|
||||
}
|
||||
|
||||
// Checks for the `None` value.
|
||||
fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
|
||||
|
||||
impl LateLintPass<'_> for ManualOkOr {
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
|
||||
if in_external_macro(cx.sess(), scrutinee.span) {
|
||||
return;
|
||||
|
@ -43,7 +43,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);
|
||||
|
||||
impl LateLintPass<'_> for ManualUnwrapOr {
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOr {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
|
||||
return;
|
||||
|
@ -55,7 +55,7 @@ enum CaseMethod {
|
||||
AsciiUppercase,
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for MatchStrCaseMismatch {
|
||||
impl<'tcx> LateLintPass<'tcx> for MatchStrCaseMismatch {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.tcx.sess, expr.span);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user