commit
238edf273d
274 changed files with 3505 additions and 2467 deletions
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
# begin autogenerated version
|
||||
version = "0.1.86"
|
||||
version = "0.1.87"
|
||||
# end autogenerated version
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_config"
|
||||
# begin autogenerated version
|
||||
version = "0.1.86"
|
||||
version = "0.1.87"
|
||||
# end autogenerated version
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
# begin autogenerated version
|
||||
version = "0.1.86"
|
||||
version = "0.1.87"
|
||||
# end autogenerated version
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
||||
use rustc_attr_parsing::RustcVersion;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{HirId, Lit};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::symbol;
|
||||
use rustc_span::{Span, symbol};
|
||||
use std::f64::consts as f64;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -73,22 +73,28 @@ impl ApproxConstant {
|
|||
msrv: conf.msrv.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
|
||||
match *lit {
|
||||
impl LateLintPass<'_> for ApproxConstant {
|
||||
fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
|
||||
match lit.node {
|
||||
LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
|
||||
FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"),
|
||||
FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
|
||||
FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
|
||||
FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"),
|
||||
FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),
|
||||
FloatTy::F32 => self.check_known_consts(cx, lit.span, s, "f32"),
|
||||
FloatTy::F64 => self.check_known_consts(cx, lit.span, s, "f64"),
|
||||
FloatTy::F128 => self.check_known_consts(cx, lit.span, s, "f128"),
|
||||
},
|
||||
// FIXME(f16_f128): add `f16` and `f128` when these types become stable.
|
||||
LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
|
||||
LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, lit.span, s, "f{32, 64}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) {
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
impl ApproxConstant {
|
||||
fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
|
||||
let s = s.as_str();
|
||||
if s.parse::<f64>().is_ok() {
|
||||
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
|
||||
|
|
@ -96,7 +102,7 @@ impl ApproxConstant {
|
|||
span_lint_and_help(
|
||||
cx,
|
||||
APPROX_CONSTANT,
|
||||
e.span,
|
||||
span,
|
||||
format!("approximate value of `{module}::consts::{name}` found"),
|
||||
None,
|
||||
"consider using the constant directly",
|
||||
|
|
@ -110,16 +116,6 @@ impl ApproxConstant {
|
|||
|
||||
impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Lit(lit) = &e.kind {
|
||||
self.check_lit(cx, &lit.node, e);
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
/// Returns `false` if the number of significant figures in `value` are
|
||||
/// less than `min_digits`; otherwise, returns true if `value` is equal
|
||||
/// to `constant`, rounded to the number of digits present in `value`.
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
|
|||
return;
|
||||
}
|
||||
|
||||
let items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
|
||||
let items = module.item_ids.iter().map(|&id| cx.tcx.hir_item(id));
|
||||
|
||||
// Iterates over the items within a module.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -60,12 +60,12 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
|
|||
// XXXkhuey maybe we should?
|
||||
return;
|
||||
},
|
||||
CoroutineSource::Block => cx.tcx.hir().body(*body_id).value,
|
||||
CoroutineSource::Block => cx.tcx.hir_body(*body_id).value,
|
||||
CoroutineSource::Closure => {
|
||||
// Like `async fn`, async closures are wrapped in an additional block
|
||||
// to move all of the closure's arguments into the future.
|
||||
|
||||
let async_closure_body = cx.tcx.hir().body(*body_id).value;
|
||||
let async_closure_body = cx.tcx.hir_body(*body_id).value;
|
||||
let ExprKind::Block(block, _) = async_closure_body.kind else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ use super::MIXED_ATTRIBUTES_STYLE;
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::{AttrKind, AttrStyle, Attribute};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_lint::{EarlyContext, LintContext};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{SourceFile, Span, Symbol};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
enum SimpleAttrKind {
|
||||
|
|
@ -79,7 +79,7 @@ fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
|
|||
);
|
||||
}
|
||||
|
||||
fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc<SourceFile>, attr_span: Span) -> bool {
|
||||
fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Arc<SourceFile>, attr_span: Span) -> bool {
|
||||
let attr_src = source_map.lookup_source_file(attr_span.lo());
|
||||
Lrc::ptr_eq(item_src, &attr_src)
|
||||
Arc::ptr_eq(item_src, &attr_src)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
|
|||
|
||||
pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
||||
if let ItemKind::Fn { body: eid, .. } = item.kind {
|
||||
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
|
||||
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
|||
|
||||
pub(super) fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
|
||||
match item.kind {
|
||||
ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
|
||||
ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> b
|
|||
match item.kind {
|
||||
TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
|
||||
TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
|
||||
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
|
||||
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Opti
|
|||
})
|
||||
},
|
||||
ExprKind::Closure(closure) => {
|
||||
let body = cx.tcx.hir().body(closure.body);
|
||||
let body = cx.tcx.hir_body(closure.body);
|
||||
let params = body
|
||||
.params
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ use clippy_utils::expr_or_init;
|
|||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
|
||||
use rustc_abi::IntegerType;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::IntegerType;
|
||||
|
||||
use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils};
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
|
||||
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
|
||||
&& cx.tcx.type_of(def_id).instantiate_identity().is_unsafe_ptr()
|
||||
&& cx.tcx.type_of(def_id).instantiate_identity().is_raw_ptr()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
|
|||
let is_read_in_closure_arg = args.iter().any(|arg| {
|
||||
if let ExprKind::Closure(closure) = arg.kind
|
||||
// To keep things simple, we only check the first param to see if its read.
|
||||
&& let Body { params: [param, ..], value } = cx.tcx.hir().body(closure.body)
|
||||
&& let Body { params: [param, ..], value } = cx.tcx.hir_body(closure.body)
|
||||
{
|
||||
!has_no_read_access(cx, param.hir_id, *value)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -145,8 +145,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::doc::DOC_NESTED_REFDEFS_INFO,
|
||||
crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO,
|
||||
crate::doc::EMPTY_DOCS_INFO,
|
||||
crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
|
||||
crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
|
||||
crate::doc::MISSING_ERRORS_DOC_INFO,
|
||||
crate::doc::MISSING_PANICS_DOC_INFO,
|
||||
crate::doc::MISSING_SAFETY_DOC_INFO,
|
||||
|
|
@ -163,6 +161,8 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
|
||||
crate::empty_drop::EMPTY_DROP_INFO,
|
||||
crate::empty_enum::EMPTY_ENUM_INFO,
|
||||
crate::empty_line_after::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
|
||||
crate::empty_line_after::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
|
||||
crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO,
|
||||
crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
|
||||
crate::endian_bytes::BIG_ENDIAN_BYTES_INFO,
|
||||
|
|
|
|||
|
|
@ -52,11 +52,10 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
|
||||
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
|
||||
let hir = cx.tcx.hir();
|
||||
// NOTE: this is different from `clippy_utils::is_inside_always_const_context`.
|
||||
// Inline const supports type inference.
|
||||
let is_parent_const = matches!(
|
||||
hir.body_const_context(hir.body_owner_def_id(body.id())),
|
||||
cx.tcx.hir_body_const_context(cx.tcx.hir_body_owner_def_id(body.id())),
|
||||
Some(ConstContext::Const { inline: false } | ConstContext::Static(_))
|
||||
);
|
||||
let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const);
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ fn try_parse_ref_op<'tcx>(
|
|||
},
|
||||
[arg],
|
||||
) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
|
||||
ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
|
||||
ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_raw_ptr() => {
|
||||
return Some((RefOp::Deref, sub_expr));
|
||||
},
|
||||
ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
&& let impl_item_hir = child.id.hir_id()
|
||||
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
|
||||
&& let ImplItemKind::Fn(_, b) = &impl_item.kind
|
||||
&& let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
|
||||
&& let Body { value: func_expr, .. } = cx.tcx.hir_body(*b)
|
||||
&& let &ty::Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
|
||||
&& let attrs = cx.tcx.hir().attrs(item.hir_id())
|
||||
&& !attrs.iter().any(|attr| attr.doc_str().is_some())
|
||||
|
|
|
|||
|
|
@ -437,8 +437,8 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
|||
walk_expr(self, expr)
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,345 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_indent};
|
||||
use clippy_utils::tokenize_with_text;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::AttrStyle;
|
||||
use rustc_ast::token::CommentKind;
|
||||
use rustc_errors::{Applicability, Diag, SuggestionStyle};
|
||||
use rustc_hir::{AttrKind, Attribute, ItemKind, Node};
|
||||
use rustc_lexer::TokenKind;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData};
|
||||
|
||||
use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
enum StopKind {
|
||||
Attr,
|
||||
Doc(CommentKind),
|
||||
}
|
||||
|
||||
impl StopKind {
|
||||
fn is_doc(self) -> bool {
|
||||
matches!(self, StopKind::Doc(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Stop {
|
||||
span: Span,
|
||||
kind: StopKind,
|
||||
first: usize,
|
||||
last: usize,
|
||||
}
|
||||
|
||||
impl Stop {
|
||||
fn convert_to_inner(&self) -> (Span, String) {
|
||||
let inner = match self.kind {
|
||||
// #|[...]
|
||||
StopKind::Attr => InnerSpan::new(1, 1),
|
||||
// /// or /**
|
||||
// ^ ^
|
||||
StopKind::Doc(_) => InnerSpan::new(2, 3),
|
||||
};
|
||||
(self.span.from_inner(inner), "!".into())
|
||||
}
|
||||
|
||||
fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) {
|
||||
match self.kind {
|
||||
StopKind::Attr => {
|
||||
if cx.tcx.sess.source_map().is_multiline(self.span) {
|
||||
suggestions.extend([
|
||||
(self.span.shrink_to_lo(), "/* ".into()),
|
||||
(self.span.shrink_to_hi(), " */".into()),
|
||||
]);
|
||||
} else {
|
||||
suggestions.push((self.span.shrink_to_lo(), "// ".into()));
|
||||
}
|
||||
},
|
||||
StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
|
||||
StopKind::Doc(CommentKind::Block) => {
|
||||
// /** outer */ /*! inner */
|
||||
// ^ ^
|
||||
let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
|
||||
suggestions.push((asterisk, String::new()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option<Self> {
|
||||
let SpanData { lo, hi, .. } = attr.span.data();
|
||||
let file = cx.tcx.sess.source_map().lookup_source_file(lo);
|
||||
|
||||
Some(Self {
|
||||
span: attr.span,
|
||||
kind: match attr.kind {
|
||||
AttrKind::Normal(_) => StopKind::Attr,
|
||||
AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
|
||||
},
|
||||
first: file.lookup_line(file.relative_position(lo))?,
|
||||
last: file.lookup_line(file.relative_position(hi))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a set of attrs/doc comments separated by 1 or more empty lines
|
||||
///
|
||||
/// ```ignore
|
||||
/// /// chunk 1 docs
|
||||
/// // not an empty line so also part of chunk 1
|
||||
/// #[chunk_1_attrs] // <-- prev_stop
|
||||
///
|
||||
/// /* gap */
|
||||
///
|
||||
/// /// chunk 2 docs // <-- next_stop
|
||||
/// #[chunk_2_attrs]
|
||||
/// ```
|
||||
struct Gap<'a> {
|
||||
/// The span of individual empty lines including the newline at the end of the line
|
||||
empty_lines: Vec<Span>,
|
||||
has_comment: bool,
|
||||
next_stop: &'a Stop,
|
||||
prev_stop: &'a Stop,
|
||||
/// The chunk that includes [`prev_stop`](Self::prev_stop)
|
||||
prev_chunk: &'a [Stop],
|
||||
}
|
||||
|
||||
impl<'a> Gap<'a> {
|
||||
fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
|
||||
let prev_stop = prev_chunk.last()?;
|
||||
let next_stop = next_chunk.first()?;
|
||||
let gap_span = prev_stop.span.between(next_stop.span);
|
||||
let gap_snippet = gap_span.get_source_text(cx)?;
|
||||
|
||||
let mut has_comment = false;
|
||||
let mut empty_lines = Vec::new();
|
||||
|
||||
for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
|
||||
match token {
|
||||
TokenKind::BlockComment {
|
||||
doc_style: None,
|
||||
terminated: true,
|
||||
}
|
||||
| TokenKind::LineComment { doc_style: None } => has_comment = true,
|
||||
TokenKind::Whitespace => {
|
||||
let newlines = source.bytes().positions(|b| b == b'\n');
|
||||
empty_lines.extend(
|
||||
newlines
|
||||
.tuple_windows()
|
||||
.map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
|
||||
.map(|inner_span| gap_span.from_inner(inner_span)),
|
||||
);
|
||||
},
|
||||
// Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
|
||||
// shenanigans
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
(!empty_lines.is_empty()).then_some(Self {
|
||||
empty_lines,
|
||||
has_comment,
|
||||
next_stop,
|
||||
prev_stop,
|
||||
prev_chunk,
|
||||
})
|
||||
}
|
||||
|
||||
fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
|
||||
self.empty_lines
|
||||
// The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
|
||||
.chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
|
||||
.map(|chunk| {
|
||||
let first = chunk.first().expect("at least one empty line");
|
||||
let last = chunk.last().expect("at least one empty line");
|
||||
// The BytePos subtraction here is safe, as before an empty line, there must be at least one
|
||||
// attribute/comment. The span needs to start at the end of the previous line.
|
||||
first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
|
||||
/// them to inner attributes/docs
|
||||
fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) {
|
||||
let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else {
|
||||
return;
|
||||
};
|
||||
let parent_desc = match cx.tcx.parent_hir_node(owner.into()) {
|
||||
Node::Item(item)
|
||||
if let ItemKind::Mod(parent_mod) = item.kind
|
||||
&& let [first, ..] = parent_mod.item_ids
|
||||
&& first.owner_id == owner =>
|
||||
{
|
||||
"parent module"
|
||||
},
|
||||
Node::Crate(crate_mod)
|
||||
if let Some(first) = crate_mod
|
||||
.item_ids
|
||||
.iter()
|
||||
.map(|&id| cx.tcx.hir().item(id))
|
||||
// skip prelude imports
|
||||
.find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
|
||||
&& first.owner_id == owner =>
|
||||
{
|
||||
"crate"
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
diag.multipart_suggestion_verbose(
|
||||
match kind {
|
||||
StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"),
|
||||
StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"),
|
||||
},
|
||||
gaps.iter()
|
||||
.flat_map(|gap| gap.prev_chunk)
|
||||
.map(Stop::convert_to_inner)
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
|
||||
let Some(first_gap) = gaps.first() else {
|
||||
return false;
|
||||
};
|
||||
let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
|
||||
let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
|
||||
let mut has_comment = false;
|
||||
let mut has_attr = false;
|
||||
for gap in gaps {
|
||||
has_comment |= gap.has_comment;
|
||||
if !has_attr {
|
||||
has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
|
||||
}
|
||||
}
|
||||
let kind = first_gap.prev_stop.kind;
|
||||
let (lint, kind_desc) = match kind {
|
||||
StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
|
||||
StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
|
||||
};
|
||||
let (lines, are, them) = if empty_lines().nth(1).is_some() {
|
||||
("lines", "are", "them")
|
||||
} else {
|
||||
("line", "is", "it")
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
|
||||
format!("empty {lines} after {kind_desc}"),
|
||||
|diag| {
|
||||
if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
|
||||
let def_id = owner.to_def_id();
|
||||
let def_descr = cx.tcx.def_descr(def_id);
|
||||
diag.span_label(
|
||||
cx.tcx.def_span(def_id),
|
||||
match kind {
|
||||
StopKind::Attr => format!("the attribute applies to this {def_descr}"),
|
||||
StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
diag.multipart_suggestion_with_style(
|
||||
format!("if the empty {lines} {are} unintentional remove {them}"),
|
||||
contiguous_empty_lines()
|
||||
.map(|empty_lines| (empty_lines, String::new()))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
|
||||
if has_comment && kind.is_doc() {
|
||||
// Likely doc comments that applied to some now commented out code
|
||||
//
|
||||
// /// Old docs for Foo
|
||||
// // struct Foo;
|
||||
|
||||
let mut suggestions = Vec::new();
|
||||
for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
|
||||
stop.comment_out(cx, &mut suggestions);
|
||||
}
|
||||
let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) {
|
||||
Some(name) => format!("`{name}`"),
|
||||
None => "this".into(),
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("if the doc comment should not document {name} comment it out"),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
suggest_inner(cx, diag, kind, gaps);
|
||||
}
|
||||
|
||||
if kind == StopKind::Doc(CommentKind::Line)
|
||||
&& gaps
|
||||
.iter()
|
||||
.all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
|
||||
{
|
||||
// Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
|
||||
|
||||
let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("if the documentation should include the empty {lines} include {them} in the comment"),
|
||||
empty_lines()
|
||||
.map(|empty_line| (empty_line, format!("{indent}///")))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
kind.is_doc()
|
||||
}
|
||||
|
||||
/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment
|
||||
/// lints where they would be confusing
|
||||
///
|
||||
/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return
|
||||
/// `true` if it triggers
|
||||
pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
|
||||
let mut outer = attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
|
||||
.map(|attr| Stop::from_attr(cx, attr))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_default();
|
||||
|
||||
if outer.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push a fake attribute Stop for the item itself so we check for gaps between the last outer
|
||||
// attr/doc comment and the item they apply to
|
||||
let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs);
|
||||
if !span.from_expansion()
|
||||
&& let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo())
|
||||
{
|
||||
outer.push(Stop {
|
||||
span,
|
||||
kind: StopKind::Attr,
|
||||
first: line.line,
|
||||
// last doesn't need to be accurate here, we don't compare it with anything
|
||||
last: line.line,
|
||||
});
|
||||
}
|
||||
|
||||
let mut gaps = Vec::new();
|
||||
let mut last = 0;
|
||||
for pos in outer
|
||||
.array_windows()
|
||||
.positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
|
||||
{
|
||||
// we want to be after the first stop in the window
|
||||
let pos = pos + 1;
|
||||
if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
|
||||
last = pos;
|
||||
gaps.push(gap);
|
||||
}
|
||||
}
|
||||
|
||||
check_gaps(cx, &gaps)
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ pub fn check(
|
|||
} else if let Some(body_id) = body_id
|
||||
&& let Some(future) = cx.tcx.lang_items().future_trait()
|
||||
&& let typeck = cx.tcx.typeck_body(body_id)
|
||||
&& let body = cx.tcx.hir().body(body_id)
|
||||
&& let body = cx.tcx.hir_body(body_id)
|
||||
&& let ret_ty = typeck.expr_ty(body.value)
|
||||
&& implements_trait_with_env(
|
||||
cx.tcx,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ use rustc_span::{Span, sym};
|
|||
use std::ops::Range;
|
||||
use url::Url;
|
||||
|
||||
mod empty_line_after;
|
||||
mod include_in_doc_without_cfg;
|
||||
mod link_with_quotes;
|
||||
mod markdown;
|
||||
|
|
@ -513,82 +512,6 @@ declare_clippy_lint! {
|
|||
"ensure the first documentation paragraph is short"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for empty lines after outer attributes
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The attribute may have meant to be an inner attribute (`#![attr]`). If
|
||||
/// it was meant to be an outer attribute (`#[attr]`) then the empty line
|
||||
/// should be removed
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// #[allow(dead_code)]
|
||||
///
|
||||
/// fn not_quite_good_code() {}
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// // Good (as inner attribute)
|
||||
/// #![allow(dead_code)]
|
||||
///
|
||||
/// fn this_is_fine() {}
|
||||
///
|
||||
/// // or
|
||||
///
|
||||
/// // Good (as outer attribute)
|
||||
/// #[allow(dead_code)]
|
||||
/// fn this_is_fine_too() {}
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
suspicious,
|
||||
"empty line after outer attribute"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for empty lines after doc comments.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The doc comment may have meant to be an inner doc comment, regular
|
||||
/// comment or applied to some old code that is now commented out. If it was
|
||||
/// intended to be a doc comment, then the empty line should be removed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// /// Some doc comment with a blank line after it.
|
||||
///
|
||||
/// fn f() {}
|
||||
///
|
||||
/// /// Docs for `old_code`
|
||||
/// // fn old_code() {}
|
||||
///
|
||||
/// fn new_code() {}
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// //! Convert it to an inner doc comment
|
||||
///
|
||||
/// // Or a regular comment
|
||||
///
|
||||
/// /// Or remove the empty line
|
||||
/// fn f() {}
|
||||
///
|
||||
/// // /// Docs for `old_code`
|
||||
/// // fn old_code() {}
|
||||
///
|
||||
/// fn new_code() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
pub EMPTY_LINE_AFTER_DOC_COMMENTS,
|
||||
suspicious,
|
||||
"empty line after doc comments"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks if included files in doc comments are included only for `cfg(doc)`.
|
||||
|
|
@ -673,8 +596,6 @@ impl_lint_pass!(Documentation => [
|
|||
EMPTY_DOCS,
|
||||
DOC_LAZY_CONTINUATION,
|
||||
DOC_OVERINDENTED_LIST_ITEMS,
|
||||
EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
EMPTY_LINE_AFTER_DOC_COMMENTS,
|
||||
TOO_LONG_FIRST_DOC_PARAGRAPH,
|
||||
DOC_INCLUDE_WITHOUT_CFG,
|
||||
]);
|
||||
|
|
@ -699,7 +620,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
|
|||
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
|
||||
|| item.span.in_external_macro(cx.tcx.sess.source_map()))
|
||||
{
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
|
||||
let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
|
||||
missing_headers::check(
|
||||
|
|
@ -751,7 +672,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
|
|||
&& !impl_item.span.in_external_macro(cx.tcx.sess.source_map())
|
||||
&& !is_trait_impl_item(cx, impl_item.hir_id())
|
||||
{
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
|
||||
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value);
|
||||
missing_headers::check(
|
||||
|
|
@ -807,7 +728,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
|
|||
}
|
||||
|
||||
include_in_doc_without_cfg::check(cx, attrs);
|
||||
if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
|
||||
if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -1256,8 +1177,8 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
|
|||
// Panics in const blocks will cause compilation to fail.
|
||||
fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{io, thread};
|
||||
|
||||
use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::HumanEmitter;
|
||||
use rustc_errors::{Diag, DiagCtxt};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -46,8 +46,8 @@ pub fn check(
|
|||
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||
let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
|
||||
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
|
||||
#[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx
|
||||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
#[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx
|
||||
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let psess = ParseSess::with_dcx(dcx, sm);
|
||||
|
||||
let mut parser = match new_parser_from_source_str(&psess, filename, code) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl LateLintPass<'_> for EmptyDrop {
|
|||
&& let impl_item_hir = child.id.hir_id()
|
||||
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
|
||||
&& let ImplItemKind::Fn(_, b) = &impl_item.kind
|
||||
&& let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
|
||||
&& let Body { value: func_expr, .. } = cx.tcx.hir_body(*b)
|
||||
&& let func_expr = peel_blocks(func_expr)
|
||||
&& let ExprKind::Block(block, _) = func_expr.kind
|
||||
&& block.stmts.is_empty()
|
||||
|
|
|
|||
495
clippy_lints/src/empty_line_after.rs
Normal file
495
clippy_lints/src/empty_line_after.rs
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_indent};
|
||||
use clippy_utils::tokenize_with_text;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::token::CommentKind;
|
||||
use rustc_ast::{AssocItemKind, AttrKind, AttrStyle, Attribute, Crate, Item, ItemKind, ModKind, NodeId};
|
||||
use rustc_errors::{Applicability, Diag, SuggestionStyle};
|
||||
use rustc_lexer::TokenKind;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for empty lines after outer attributes
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The attribute may have meant to be an inner attribute (`#![attr]`). If
|
||||
/// it was meant to be an outer attribute (`#[attr]`) then the empty line
|
||||
/// should be removed
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// #[allow(dead_code)]
|
||||
///
|
||||
/// fn not_quite_good_code() {}
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// // Good (as inner attribute)
|
||||
/// #![allow(dead_code)]
|
||||
///
|
||||
/// fn this_is_fine() {}
|
||||
///
|
||||
/// // or
|
||||
///
|
||||
/// // Good (as outer attribute)
|
||||
/// #[allow(dead_code)]
|
||||
/// fn this_is_fine_too() {}
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
suspicious,
|
||||
"empty line after outer attribute"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for empty lines after doc comments.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The doc comment may have meant to be an inner doc comment, regular
|
||||
/// comment or applied to some old code that is now commented out. If it was
|
||||
/// intended to be a doc comment, then the empty line should be removed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// /// Some doc comment with a blank line after it.
|
||||
///
|
||||
/// fn f() {}
|
||||
///
|
||||
/// /// Docs for `old_code`
|
||||
/// // fn old_code() {}
|
||||
///
|
||||
/// fn new_code() {}
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// //! Convert it to an inner doc comment
|
||||
///
|
||||
/// // Or a regular comment
|
||||
///
|
||||
/// /// Or remove the empty line
|
||||
/// fn f() {}
|
||||
///
|
||||
/// // /// Docs for `old_code`
|
||||
/// // fn old_code() {}
|
||||
///
|
||||
/// fn new_code() {}
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
pub EMPTY_LINE_AFTER_DOC_COMMENTS,
|
||||
suspicious,
|
||||
"empty line after doc comments"
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ItemInfo {
|
||||
kind: &'static str,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
mod_items: Option<NodeId>,
|
||||
}
|
||||
|
||||
pub struct EmptyLineAfter {
|
||||
items: Vec<ItemInfo>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(EmptyLineAfter => [
|
||||
EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
EMPTY_LINE_AFTER_DOC_COMMENTS,
|
||||
]);
|
||||
|
||||
impl EmptyLineAfter {
|
||||
pub fn new() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
enum StopKind {
|
||||
Attr,
|
||||
Doc(CommentKind),
|
||||
}
|
||||
|
||||
impl StopKind {
|
||||
fn is_doc(self) -> bool {
|
||||
matches!(self, StopKind::Doc(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Stop {
|
||||
span: Span,
|
||||
kind: StopKind,
|
||||
first: usize,
|
||||
last: usize,
|
||||
}
|
||||
|
||||
impl Stop {
|
||||
fn convert_to_inner(&self) -> (Span, String) {
|
||||
let inner = match self.kind {
|
||||
// #![...]
|
||||
StopKind::Attr => InnerSpan::new(1, 1),
|
||||
// /// or /**
|
||||
// ^ ^
|
||||
StopKind::Doc(_) => InnerSpan::new(2, 3),
|
||||
};
|
||||
(self.span.from_inner(inner), "!".into())
|
||||
}
|
||||
|
||||
fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
|
||||
match self.kind {
|
||||
StopKind::Attr => {
|
||||
if cx.sess().source_map().is_multiline(self.span) {
|
||||
suggestions.extend([
|
||||
(self.span.shrink_to_lo(), "/* ".into()),
|
||||
(self.span.shrink_to_hi(), " */".into()),
|
||||
]);
|
||||
} else {
|
||||
suggestions.push((self.span.shrink_to_lo(), "// ".into()));
|
||||
}
|
||||
},
|
||||
StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
|
||||
StopKind::Doc(CommentKind::Block) => {
|
||||
// /** outer */ /*! inner */
|
||||
// ^ ^
|
||||
let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
|
||||
suggestions.push((asterisk, String::new()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn from_attr(cx: &EarlyContext<'_>, attr: &Attribute) -> Option<Self> {
|
||||
let SpanData { lo, hi, .. } = attr.span.data();
|
||||
let file = cx.sess().source_map().lookup_source_file(lo);
|
||||
|
||||
Some(Self {
|
||||
span: attr.span,
|
||||
kind: match attr.kind {
|
||||
AttrKind::Normal(_) => StopKind::Attr,
|
||||
AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
|
||||
},
|
||||
first: file.lookup_line(file.relative_position(lo))?,
|
||||
last: file.lookup_line(file.relative_position(hi))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a set of attrs/doc comments separated by 1 or more empty lines
|
||||
///
|
||||
/// ```ignore
|
||||
/// /// chunk 1 docs
|
||||
/// // not an empty line so also part of chunk 1
|
||||
/// #[chunk_1_attrs] // <-- prev_stop
|
||||
///
|
||||
/// /* gap */
|
||||
///
|
||||
/// /// chunk 2 docs // <-- next_stop
|
||||
/// #[chunk_2_attrs]
|
||||
/// ```
|
||||
struct Gap<'a> {
|
||||
/// The span of individual empty lines including the newline at the end of the line
|
||||
empty_lines: Vec<Span>,
|
||||
has_comment: bool,
|
||||
next_stop: &'a Stop,
|
||||
prev_stop: &'a Stop,
|
||||
/// The chunk that includes [`prev_stop`](Self::prev_stop)
|
||||
prev_chunk: &'a [Stop],
|
||||
}
|
||||
|
||||
impl<'a> Gap<'a> {
|
||||
fn new(cx: &EarlyContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
|
||||
let prev_stop = prev_chunk.last()?;
|
||||
let next_stop = next_chunk.first()?;
|
||||
let gap_span = prev_stop.span.between(next_stop.span);
|
||||
let gap_snippet = gap_span.get_source_text(cx)?;
|
||||
|
||||
let mut has_comment = false;
|
||||
let mut empty_lines = Vec::new();
|
||||
|
||||
for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
|
||||
match token {
|
||||
TokenKind::BlockComment {
|
||||
doc_style: None,
|
||||
terminated: true,
|
||||
}
|
||||
| TokenKind::LineComment { doc_style: None } => has_comment = true,
|
||||
TokenKind::Whitespace => {
|
||||
let newlines = source.bytes().positions(|b| b == b'\n');
|
||||
empty_lines.extend(
|
||||
newlines
|
||||
.tuple_windows()
|
||||
.map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
|
||||
.map(|inner_span| gap_span.from_inner(inner_span)),
|
||||
);
|
||||
},
|
||||
// Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
|
||||
// shenanigans
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
(!empty_lines.is_empty()).then_some(Self {
|
||||
empty_lines,
|
||||
has_comment,
|
||||
next_stop,
|
||||
prev_stop,
|
||||
prev_chunk,
|
||||
})
|
||||
}
|
||||
|
||||
fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
|
||||
self.empty_lines
|
||||
// The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
|
||||
.chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
|
||||
.map(|chunk| {
|
||||
let first = chunk.first().expect("at least one empty line");
|
||||
let last = chunk.last().expect("at least one empty line");
|
||||
// The BytePos subtraction here is safe, as before an empty line, there must be at least one
|
||||
// attribute/comment. The span needs to start at the end of the previous line.
|
||||
first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EmptyLineAfter {
|
||||
fn check_gaps(&self, cx: &EarlyContext<'_>, gaps: &[Gap<'_>], id: NodeId) {
|
||||
let Some(first_gap) = gaps.first() else {
|
||||
return;
|
||||
};
|
||||
let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
|
||||
let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
|
||||
let mut has_comment = false;
|
||||
let mut has_attr = false;
|
||||
for gap in gaps {
|
||||
has_comment |= gap.has_comment;
|
||||
if !has_attr {
|
||||
has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
|
||||
}
|
||||
}
|
||||
let kind = first_gap.prev_stop.kind;
|
||||
let (lint, kind_desc) = match kind {
|
||||
StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
|
||||
StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
|
||||
};
|
||||
let (lines, are, them) = if empty_lines().nth(1).is_some() {
|
||||
("lines", "are", "them")
|
||||
} else {
|
||||
("line", "is", "it")
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
|
||||
format!("empty {lines} after {kind_desc}"),
|
||||
|diag| {
|
||||
let info = self.items.last().unwrap();
|
||||
diag.span_label(
|
||||
info.span,
|
||||
match kind {
|
||||
StopKind::Attr => format!("the attribute applies to this {}", info.kind),
|
||||
StopKind::Doc(_) => format!("the comment documents this {}", info.kind),
|
||||
},
|
||||
);
|
||||
|
||||
diag.multipart_suggestion_with_style(
|
||||
format!("if the empty {lines} {are} unintentional, remove {them}"),
|
||||
contiguous_empty_lines()
|
||||
.map(|empty_lines| (empty_lines, String::new()))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
|
||||
if has_comment && kind.is_doc() {
|
||||
// Likely doc comments that applied to some now commented out code
|
||||
//
|
||||
// /// Old docs for Foo
|
||||
// // struct Foo;
|
||||
|
||||
let mut suggestions = Vec::new();
|
||||
for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
|
||||
stop.comment_out(cx, &mut suggestions);
|
||||
}
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("if the doc comment should not document `{}` comment it out", info.name),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
self.suggest_inner(diag, kind, gaps, id);
|
||||
}
|
||||
|
||||
if kind == StopKind::Doc(CommentKind::Line)
|
||||
&& gaps
|
||||
.iter()
|
||||
.all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
|
||||
{
|
||||
// Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
|
||||
|
||||
let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("if the documentation should include the empty {lines} include {them} in the comment"),
|
||||
empty_lines()
|
||||
.map(|empty_line| (empty_line, format!("{indent}///")))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
|
||||
/// them to inner attributes/docs
|
||||
fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>], id: NodeId) {
|
||||
if let Some(parent) = self.items.iter().rev().nth(1)
|
||||
&& (parent.kind == "module" || parent.kind == "crate")
|
||||
&& parent.mod_items == Some(id)
|
||||
{
|
||||
let desc = if parent.kind == "module" {
|
||||
"parent module"
|
||||
} else {
|
||||
parent.kind
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
match kind {
|
||||
StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
|
||||
StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
|
||||
},
|
||||
gaps.iter()
|
||||
.flat_map(|gap| gap.prev_chunk)
|
||||
.map(Stop::convert_to_inner)
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item_kind(
|
||||
&mut self,
|
||||
cx: &EarlyContext<'_>,
|
||||
kind: &ItemKind,
|
||||
ident: &Ident,
|
||||
span: Span,
|
||||
attrs: &[Attribute],
|
||||
id: NodeId,
|
||||
) {
|
||||
self.items.push(ItemInfo {
|
||||
kind: kind.descr(),
|
||||
name: ident.name,
|
||||
span: if span.contains(ident.span) {
|
||||
span.with_hi(ident.span.hi())
|
||||
} else {
|
||||
span.with_hi(span.lo())
|
||||
},
|
||||
mod_items: match kind {
|
||||
ItemKind::Mod(_, ModKind::Loaded(items, _, _, _)) => items
|
||||
.iter()
|
||||
.filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
|
||||
.map(|i| i.id)
|
||||
.next(),
|
||||
_ => None,
|
||||
},
|
||||
});
|
||||
|
||||
let mut outer = attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
|
||||
.map(|attr| Stop::from_attr(cx, attr))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_default();
|
||||
|
||||
if outer.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Push a fake attribute Stop for the item itself so we check for gaps between the last outer
|
||||
// attr/doc comment and the item they apply to
|
||||
let span = self.items.last().unwrap().span;
|
||||
if !span.from_expansion()
|
||||
&& let Ok(line) = cx.sess().source_map().lookup_line(span.lo())
|
||||
{
|
||||
outer.push(Stop {
|
||||
span,
|
||||
kind: StopKind::Attr,
|
||||
first: line.line,
|
||||
// last doesn't need to be accurate here, we don't compare it with anything
|
||||
last: line.line,
|
||||
});
|
||||
}
|
||||
|
||||
let mut gaps = Vec::new();
|
||||
let mut last = 0;
|
||||
for pos in outer
|
||||
.array_windows()
|
||||
.positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
|
||||
{
|
||||
// we want to be after the first stop in the window
|
||||
let pos = pos + 1;
|
||||
if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
|
||||
last = pos;
|
||||
gaps.push(gap);
|
||||
}
|
||||
}
|
||||
|
||||
self.check_gaps(cx, &gaps, id);
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for EmptyLineAfter {
|
||||
fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
|
||||
self.items.push(ItemInfo {
|
||||
kind: "crate",
|
||||
name: kw::Crate,
|
||||
span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
|
||||
mod_items: krate
|
||||
.items
|
||||
.iter()
|
||||
.filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
|
||||
.map(|i| i.id)
|
||||
.next(),
|
||||
});
|
||||
}
|
||||
|
||||
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
|
||||
self.items.pop();
|
||||
}
|
||||
fn check_impl_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
|
||||
self.items.pop();
|
||||
}
|
||||
fn check_trait_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
|
||||
self.items.pop();
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
|
||||
self.check_item_kind(
|
||||
cx,
|
||||
&item.kind.clone().into(),
|
||||
&item.ident,
|
||||
item.span,
|
||||
&item.attrs,
|
||||
item.id,
|
||||
);
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
|
||||
self.check_item_kind(
|
||||
cx,
|
||||
&item.kind.clone().into(),
|
||||
&item.ident,
|
||||
item.span,
|
||||
&item.attrs,
|
||||
item.id,
|
||||
);
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
self.check_item_kind(cx, &item.kind, &item.ident, item.span, &item.attrs, item.id);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
|||
if let ItemKind::Enum(def, _) = &item.kind {
|
||||
for var in def.variants {
|
||||
if let Some(anon_const) = &var.disr_expr {
|
||||
let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
|
||||
let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);
|
||||
let mut ty = cx.tcx.type_of(def_id.to_def_id()).instantiate_identity();
|
||||
let constant = cx
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir;
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::{AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind, intravisit};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -10,7 +11,6 @@ use rustc_session::impl_lint_pass;
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
pub struct BoxedLocal {
|
||||
too_large_for_stack: u64,
|
||||
|
|
@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
fn_def_id: LocalDefId,
|
||||
) {
|
||||
if let Some(header) = fn_kind.header() {
|
||||
if header.abi != Abi::Rust {
|
||||
if header.abi != ExternAbi::Rust {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use clippy_utils::usage::{local_used_after_expr, local_used_in};
|
|||
use clippy_utils::{
|
||||
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
|
||||
};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
|
@ -15,7 +16,6 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -97,7 +97,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
&& matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
|
||||
&& !expr.span.from_expansion()
|
||||
{
|
||||
cx.tcx.hir().body(c.body)
|
||||
cx.tcx.hir_body(c.body)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -172,7 +172,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
&& let output = typeck.expr_ty(body.value)
|
||||
&& let ty::Tuple(tys) = *subs.type_at(1).kind()
|
||||
{
|
||||
cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
|
||||
cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, ExternAbi::Rust)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
|||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
|
||||
// functions with a body are already checked by `check_fn`
|
||||
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
|
||||
&& fn_sig.header.abi == Abi::Rust
|
||||
&& fn_sig.header.abi == ExternAbi::Rust
|
||||
&& fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools
|
||||
{
|
||||
check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools);
|
||||
|
|
@ -162,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
|||
def_id: LocalDefId,
|
||||
) {
|
||||
if let Some(fn_header) = fn_kind.header()
|
||||
&& fn_header.abi == Abi::Rust
|
||||
&& fn_header.abi == ExternAbi::Rust
|
||||
&& fn_decl.inputs.len() as u64 > self.max_fn_params_bools
|
||||
&& get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
|
||||
.is_none_or(|impl_item| impl_item.of_trait.is_none())
|
||||
|
|
|
|||
|
|
@ -241,13 +241,13 @@ impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool {
|
||||
matches!(cx.tcx.hir().body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
|
||||
matches!(cx.tcx.hir_body(body).value.kind, ExprKind::Block(b, _) if b.stmts.is_empty() && b.expr.is_none())
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||
|
|
|
|||
|
|
@ -98,10 +98,10 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
|
|||
|
||||
for impl_item in impl_items {
|
||||
if impl_item.ident.name == sym::from
|
||||
&& let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind
|
||||
&& let ImplItemKind::Fn(_, body_id) = cx.tcx.hir_impl_item(impl_item.id).kind
|
||||
{
|
||||
// check the body for `begin_panic` or `unwrap`
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
let mut fpu = FindPanicUnwrap {
|
||||
lcx: cx,
|
||||
typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
|
|||
&& let Some(name) = cx.tcx.get_diagnostic_name(did)
|
||||
&& matches!(name, sym::Debug | sym::Display)
|
||||
{
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
let formatter_name = body
|
||||
.params
|
||||
.get(1)
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
|
|||
type Result = ControlFlow<()>;
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result {
|
||||
|
|
@ -175,11 +175,11 @@ fn convert_to_from(
|
|||
// bad suggestion/fix.
|
||||
return None;
|
||||
}
|
||||
let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
|
||||
let impl_item = cx.tcx.hir_impl_item(impl_item_ref.id);
|
||||
let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else {
|
||||
return None;
|
||||
};
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
let [input] = body.params else { return None };
|
||||
let PatKind::Binding(.., self_ident, None) = input.pat.kind else {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
|
|||
|
||||
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
|
||||
if let FnKind::ItemFn(_, generics, _) = kind
|
||||
&& cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
|
||||
&& cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
|
||||
&& !is_in_test(cx.tcx, hir_id)
|
||||
{
|
||||
for param in generics.params {
|
||||
|
|
@ -56,8 +56,8 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
|
|||
&& let hir::ItemKind::Impl(impl_) = item.kind
|
||||
&& let hir::Impl { of_trait, .. } = *impl_
|
||||
&& of_trait.is_none()
|
||||
&& let body = cx.tcx.hir().body(body_id)
|
||||
&& cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
|
||||
&& let body = cx.tcx.hir_body(body_id)
|
||||
&& cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
|
||||
&& !is_in_test(cx.tcx, impl_item.hir_id())
|
||||
{
|
||||
for param in impl_item.generics.params {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
|
|||
check_must_use_candidate(
|
||||
cx,
|
||||
sig.decl,
|
||||
cx.tcx.hir().body(*body_id),
|
||||
cx.tcx.hir_body(*body_id),
|
||||
item.span,
|
||||
item.owner_id,
|
||||
item.span.with_hi(sig.decl.output.span().hi()),
|
||||
|
|
@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
|||
check_must_use_candidate(
|
||||
cx,
|
||||
sig.decl,
|
||||
cx.tcx.hir().body(*body_id),
|
||||
cx.tcx.hir_body(*body_id),
|
||||
item.span,
|
||||
item.owner_id,
|
||||
item.span.with_hi(sig.decl.output.span().hi()),
|
||||
|
|
@ -79,7 +79,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
|
||||
} else if let hir::TraitFn::Provided(eid) = *eid {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
let body = cx.tcx.hir_body(eid);
|
||||
if attr.is_none() && is_public && !is_proc_macro(attrs) {
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub(super) fn check_fn<'tcx>(
|
|||
|
||||
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);
|
||||
let body = cx.tcx.hir_body(eid);
|
||||
check_raw_ptr(cx, sig.header.safety(), sig.decl, body, item.owner_id.def_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
|
|||
&& let Some(did) = trait_item_def_id_of_impl(items, item.owner_id)
|
||||
&& !is_from_ignored_trait(trait_ref, ignored_traits)
|
||||
{
|
||||
let mut param_idents_iter = cx.tcx.hir().body_param_names(body_id);
|
||||
let mut param_idents_iter = cx.tcx.hir_body_param_names(body_id);
|
||||
let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied();
|
||||
|
||||
let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::{self as hir, intravisit};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_trait_impl_item;
|
||||
|
|
@ -23,11 +23,19 @@ pub(super) fn check_fn(
|
|||
intravisit::FnKind::Method(
|
||||
_,
|
||||
&hir::FnSig {
|
||||
header: hir::FnHeader { abi: Abi::Rust, .. },
|
||||
header: hir::FnHeader {
|
||||
abi: ExternAbi::Rust, ..
|
||||
},
|
||||
..
|
||||
},
|
||||
)
|
||||
| intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }) => check_arg_number(
|
||||
| intravisit::FnKind::ItemFn(
|
||||
_,
|
||||
_,
|
||||
hir::FnHeader {
|
||||
abi: ExternAbi::Rust, ..
|
||||
},
|
||||
) => check_arg_number(
|
||||
cx,
|
||||
decl,
|
||||
span.with_hi(decl.output.span().hi()),
|
||||
|
|
@ -41,7 +49,7 @@ pub(super) fn check_fn(
|
|||
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 {
|
||||
if sig.header.abi == ExternAbi::Rust {
|
||||
check_arg_number(
|
||||
cx,
|
||||
sig.decl,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
|||
});
|
||||
|
||||
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
|
||||
for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
|
||||
for item in impl_.items.iter().map(|item| cx.tcx.hir_impl_item(item.id)) {
|
||||
ctr_vis.visit_impl_item(item);
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
|||
body: body_id,
|
||||
..
|
||||
} => {
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
|
||||
for ty in sig.decl.inputs {
|
||||
let mut vis = ImplicitHasherTypeVisitor::new(cx);
|
||||
|
|
@ -363,7 +363,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
|
|||
walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,8 +223,8 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
|
|||
impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
|||
}
|
||||
if method.ident.name.as_str() == "flat_map" && args.len() == 1 {
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body = cx.tcx.hir_body(body);
|
||||
return is_infinite(cx, body.value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
|||
// #11201
|
||||
&& let header = signature.header
|
||||
&& header.is_safe()
|
||||
&& header.abi == Abi::Rust
|
||||
&& header.abi == ExternAbi::Rust
|
||||
&& impl_item.ident.name == sym::to_string
|
||||
&& let decl = signature.decl
|
||||
&& decl.implicit_self.has_implicit_self()
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl LateLintPass<'_> for ItemsAfterStatements {
|
|||
.iter()
|
||||
.skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
|
||||
.filter_map(|stmt| match stmt.kind {
|
||||
StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
|
||||
StmtKind::Item(id) => Some(cx.tcx.hir_item(id)),
|
||||
_ => None,
|
||||
})
|
||||
// Ignore macros since they can only see previously defined locals.
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
|
|||
|
||||
impl LateLintPass<'_> for ItemsAfterTestModule {
|
||||
fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
|
||||
let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
|
||||
let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir_item(id));
|
||||
|
||||
let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
|
||||
return;
|
||||
|
|
@ -91,7 +91,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
|
|||
"items after a test module",
|
||||
|diag| {
|
||||
if let Some(prev) = mod_pos.checked_sub(1)
|
||||
&& let prev = cx.tcx.hir().item(module.item_ids[prev])
|
||||
&& let prev = cx.tcx.hir_item(module.item_ids[prev])
|
||||
&& let items_span = last.span.with_lo(test_mod.span.hi())
|
||||
&& let Some(items) = items_span.get_source_text(cx)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
|
|||
})
|
||||
&& let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
|
||||
if item.ident.name.as_str() == "IntoIter" {
|
||||
Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
|
||||
Some(cx.tcx.hir_impl_item(item.id).expect_type().span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_abi::Size;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ enum LenOutput {
|
|||
|
||||
fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
|
||||
if let ty::Alias(_, alias_ty) = ty.kind()
|
||||
&& let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
|
||||
&& let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir_get_if_local(alias_ty.def_id)
|
||||
&& let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin
|
||||
&& let [GenericBound::Trait(trait_ref)] = &opaque.bounds
|
||||
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![feature(f128)]
|
||||
|
|
@ -125,6 +126,7 @@ mod duplicate_mod;
|
|||
mod else_if_without_else;
|
||||
mod empty_drop;
|
||||
mod empty_enum;
|
||||
mod empty_line_after;
|
||||
mod empty_with_brackets;
|
||||
mod endian_bytes;
|
||||
mod entry;
|
||||
|
|
@ -973,6 +975,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
|
||||
store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
|
||||
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
|
||||
store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ use rustc_hir::{
|
|||
WherePredicateKind, lang_items,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
|
@ -275,7 +275,7 @@ fn could_use_elision<'tcx>(
|
|||
}
|
||||
|
||||
if let Some(body_id) = body {
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
|
||||
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
|
||||
if non_elidable_self_type(cx, func, first_ident, msrv) {
|
||||
|
|
@ -582,7 +582,7 @@ impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
|
|||
where
|
||||
F: NestedFilter<'tcx>,
|
||||
{
|
||||
type Map = Map<'tcx>;
|
||||
type MaybeTyCtxt = TyCtxt<'tcx>;
|
||||
type NestedFilter = F;
|
||||
|
||||
// for lifetimes as parameters of generics
|
||||
|
|
@ -628,8 +628,8 @@ where
|
|||
self.lifetime_elision_impossible = false;
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
|
|||
ExprKind::Closure(Closure { body, .. }) => {
|
||||
if let Body {
|
||||
params: [param], value, ..
|
||||
} = cx.tcx.hir().body(*body)
|
||||
} = cx.tcx.hir_body(*body)
|
||||
&& let ExprKind::MethodCall(method, receiver, [], _) = value.kind
|
||||
&& path_to_local_id(receiver, param.pat.hir_id)
|
||||
&& let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
|
|||
}
|
||||
},
|
||||
ExprKind::Closure(&Closure { body, .. }) => {
|
||||
let body = self.cx.tcx.hir().body(body);
|
||||
let body = self.cx.tcx.hir_body(body);
|
||||
self.visit_expr(body.value);
|
||||
},
|
||||
_ => walk_expr(self, expr),
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -245,8 +245,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
type Result = ControlFlow<()>;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
|
||||
|
|
@ -288,8 +288,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
}
|
||||
impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
|
||||
|
|
@ -351,7 +351,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
loop_id: loop_expr.hir_id,
|
||||
after_loop: false,
|
||||
};
|
||||
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value)
|
||||
v.visit_expr(cx.tcx.hir_body(cx.enclosing_body.unwrap()).value)
|
||||
.is_break()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
|
|||
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) =
|
||||
kind
|
||||
{
|
||||
return Some(cx.tcx.hir().body(body));
|
||||
return Some(cx.tcx.hir_body(body));
|
||||
}
|
||||
|
||||
None
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
|||
&& exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
|
||||
&& !expr.span.in_external_macro(cx.sess().source_map())
|
||||
&& (
|
||||
is_not_const(cx.tcx, cx.tcx.hir().enclosing_body_owner(expr.hir_id).into())
|
||||
is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into())
|
||||
|| self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY)
|
||||
)
|
||||
&& let [first, second, const_1, const_2] = exprs
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> b
|
|||
fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
|
||||
ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir().body(cl.body).value),
|
||||
ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir_body(cl.body).value),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ fn check_into_iter(
|
|||
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
|
||||
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = target_expr.kind
|
||||
&& let hir::ExprKind::Closure(closure) = closure_expr.kind
|
||||
&& let filter_body = cx.tcx.hir().body(closure.body)
|
||||
&& let filter_body = cx.tcx.hir_body(closure.body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
{
|
||||
if match_map_type(cx, left_expr) {
|
||||
|
|
@ -139,7 +139,7 @@ fn check_iter(
|
|||
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
|
||||
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
|
||||
&& let hir::ExprKind::Closure(closure) = closure_expr.kind
|
||||
&& let filter_body = cx.tcx.hir().body(closure.body)
|
||||
&& let filter_body = cx.tcx.hir_body(closure.body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
{
|
||||
match filter_params.pat.kind {
|
||||
|
|
@ -198,7 +198,7 @@ fn check_to_owned(
|
|||
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
|
||||
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
|
||||
&& let hir::ExprKind::Closure(closure) = closure_expr.kind
|
||||
&& let filter_body = cx.tcx.hir().body(closure.body)
|
||||
&& let filter_body = cx.tcx.hir_body(closure.body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
{
|
||||
if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ fn unit_closure<'tcx>(
|
|||
expr: &hir::Expr<'_>,
|
||||
) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let body_expr = &body.value
|
||||
&& fn_decl.inputs.len() == 1
|
||||
&& is_unit_expression(cx, body_expr)
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ impl BindInsteadOfMap {
|
|||
|
||||
match arg.kind {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
|
||||
if self.lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
|
|||
filter_arg: &'tcx Expr<'_>,
|
||||
) {
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let [param] = body.params
|
||||
&& let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind
|
||||
&& let ExprKind::Binary(ref op, l, r) = body.value.kind
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool
|
|||
ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name,
|
||||
ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
|
||||
ExprKind::Closure(Closure { body, .. }) => {
|
||||
let body = cx.tcx.hir().body(*body);
|
||||
let body = cx.tcx.hir_body(*body);
|
||||
let closure_expr = peel_blocks(body.value);
|
||||
match closure_expr.kind {
|
||||
ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => {
|
||||
|
|
@ -403,7 +403,7 @@ fn is_find_or_filter<'a>(
|
|||
if is_trait_method(cx, map_recv, sym::Iterator)
|
||||
// filter(|x| ...is_some())...
|
||||
&& let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
|
||||
&& let filter_body = cx.tcx.hir().body(filter_body_id)
|
||||
&& let filter_body = cx.tcx.hir_body(filter_body_id)
|
||||
&& let [filter_param] = filter_body.params
|
||||
// optional ref pattern: `filter(|&x| ..)`
|
||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
|
|
@ -416,7 +416,7 @@ fn is_find_or_filter<'a>(
|
|||
&& let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
|
||||
|
||||
&& let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
|
||||
&& let map_body = cx.tcx.hir().body(map_body_id)
|
||||
&& let map_body = cx.tcx.hir_body(map_body_id)
|
||||
&& let [map_param] = map_body.params
|
||||
&& let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
|
|||
if !expr.span.in_external_macro(cx.sess().source_map())
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& let ExprKind::Closure(closure) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(closure.body)
|
||||
&& let body = cx.tcx.hir_body(closure.body)
|
||||
&& let value = peel_blocks(body.value)
|
||||
// Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
|
||||
// `inputs` and `params` here as we need both the type and the span
|
||||
|
|
@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
|
|||
&& is_copy(cx, param_ty)
|
||||
&& let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
|
||||
&& let ExprKind::Closure(then_closure) = then_arg.kind
|
||||
&& let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
|
||||
&& let then_body = peel_blocks(cx.tcx.hir_body(then_closure.body).value)
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::bool_then, def_id)
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>
|
|||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
|
||||
if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
|
||||
&& let ExprKind::Closure(closure) = map_arg.kind
|
||||
&& let body = cx.tcx.hir().body(closure.body)
|
||||
&& let body = cx.tcx.hir_body(closure.body)
|
||||
&& let Some(value) = peel_non_expn_blocks(body.value)
|
||||
&& let Some(mac) = root_macro_call_first_node(cx, value)
|
||||
&& is_format_macro(cx, mac.def_id)
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ fn is_method(
|
|||
false
|
||||
},
|
||||
ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(body.value);
|
||||
let params = body.params.iter().map(|param| param.pat).collect::<Vec<_>>();
|
||||
is_method(cx, closure_expr, type_symbol, method_name, params.as_slice())
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
|
|||
&& let Body {
|
||||
params: [p],
|
||||
value: body_expr,
|
||||
} = cx.tcx.hir().body(c.body)
|
||||
} = cx.tcx.hir_body(c.body)
|
||||
&& let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
|
||||
&& let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
|
||||
(key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
|
|||
let ExprKind::Closure(closure) = expr.kind else {
|
||||
return;
|
||||
};
|
||||
let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else {
|
||||
let body @ Body { params: [p], .. } = cx.tcx.hir_body(closure.body) else {
|
||||
return;
|
||||
};
|
||||
let mut delegate = MoveDelegate {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, clos
|
|||
if !expr.span.from_expansion()
|
||||
// check if `iter().any()` can be replaced with `contains()`
|
||||
&& let ExprKind::Closure(closure) = closure_arg.kind
|
||||
&& let Body{params: [param],value} = cx.tcx.hir().body(closure.body)
|
||||
&& let Body{params: [param],value} = cx.tcx.hir_body(closure.body)
|
||||
&& let ExprKind::Binary(op, lhs, rhs) = value.kind
|
||||
&& let (peeled_ref_pat, _) = peel_hir_pat_refs(param.pat)
|
||||
&& let Some((snip,snip_expr)) = can_replace_with_contains(cx, op, lhs, rhs, peeled_ref_pat.hir_id, &mut app)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
|
|||
&& (is_diag_trait_item(cx, fn_id, sym::Iterator)
|
||||
|| (msrv.meets(msrvs::OPTION_RESULT_INSPECT)
|
||||
&& (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result))))
|
||||
&& let body = cx.tcx.hir().body(c.body)
|
||||
&& let body = cx.tcx.hir_body(c.body)
|
||||
&& let [param] = body.params
|
||||
&& let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind
|
||||
&& let arg_ty = typeck.node_type(arg_id)
|
||||
|
|
@ -45,7 +45,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
|
|||
let can_lint = for_each_expr_without_closures(block.stmts, |e| {
|
||||
if let ExprKind::Closure(c) = e.kind {
|
||||
// Nested closures don't need to treat returns specially.
|
||||
let _: Option<!> = for_each_expr(cx, cx.tcx.hir().body(c.body).value, |e| {
|
||||
let _: Option<!> = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| {
|
||||
if path_to_local_id(e, arg_id) {
|
||||
let (kind, same_ctxt) = check_use(cx, e);
|
||||
match (kind, same_ctxt && e.span.ctxt() == ctxt) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
|
|||
match map_expr.kind {
|
||||
ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true,
|
||||
ExprKind::Closure(closure) => {
|
||||
let body = cx.tcx.hir().body(closure.body);
|
||||
let body = cx.tcx.hir_body(closure.body);
|
||||
if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind
|
||||
&& let ExprKind::Call(callee, [ok_arg]) = body.value.kind
|
||||
&& is_res_lang_ctor(cx, path_res(cx, callee), ResultOk)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
|
|||
{
|
||||
match arg.kind {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
match closure_body.params[0].pat.kind {
|
||||
hir::PatKind::Ref(inner, Mutability::Not) => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
|
|||
fn_decl_span,
|
||||
..
|
||||
}) = arg.kind
|
||||
&& let closure_body = cx.tcx.hir().body(body)
|
||||
&& let closure_body = cx.tcx.hir_body(body)
|
||||
&& let [param] = closure_body.params
|
||||
&& let PatKind::Wild = param.pat.kind
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ pub(super) fn check(
|
|||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
if let Some(range) = higher::Range::hir(receiver)
|
||||
&& let ExprKind::Closure(Closure { body, .. }) = arg.kind
|
||||
&& let body_hir = cx.tcx.hir().body(*body)
|
||||
&& let body_hir = cx.tcx.hir_body(*body)
|
||||
&& let Body {
|
||||
params: [param],
|
||||
value: body_expr,
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ use clippy_utils::msrvs::{self, Msrv};
|
|||
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
|
||||
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
|
||||
|
|
@ -4749,7 +4750,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
if sig.decl.implicit_self.has_implicit_self()
|
||||
&& !(self.avoid_breaking_exported_api
|
||||
&& cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
|
||||
&& let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
|
||||
&& let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir_body(id)).next()
|
||||
&& let Some(first_arg_ty) = first_arg_ty_opt
|
||||
{
|
||||
wrong_self_convention::check(
|
||||
|
|
@ -4885,7 +4886,7 @@ impl Methods {
|
|||
),
|
||||
Some(("chars", recv, _, _, _))
|
||||
if let ExprKind::Closure(arg) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(arg.body)
|
||||
&& let body = cx.tcx.hir_body(arg.body)
|
||||
&& let [param] = body.params =>
|
||||
{
|
||||
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
|
||||
|
|
@ -5488,7 +5489,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
|
|||
safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
abi: rustc_target::spec::abi::Abi::Rust,
|
||||
abi: ExternAbi::Rust,
|
||||
};
|
||||
|
||||
struct ShouldImplTraitCase {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ fn handle_expr(
|
|||
|
||||
pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) {
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let Some(first_param) = body.params.first()
|
||||
&& let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind
|
||||
&& method.ident.name.as_str() == "chars"
|
||||
|
|
|
|||
|
|
@ -456,8 +456,8 @@ impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +498,7 @@ fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet {
|
|||
}
|
||||
},
|
||||
ty::Closure(def_id, _) => {
|
||||
let closure_hir_node = cx.tcx.hir().get_if_local(*def_id).unwrap();
|
||||
let closure_hir_node = cx.tcx.hir_get_if_local(*def_id).unwrap();
|
||||
if let Node::Expr(closure_expr) = closure_hir_node {
|
||||
can_move_expr_to_closure(cx, closure_expr)
|
||||
.unwrap()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
|
|||
|
||||
let if_then = match then_method_name {
|
||||
"then" if let ExprKind::Closure(closure) = then_arg.kind => {
|
||||
let body = cx.tcx.hir().body(closure.body);
|
||||
let body = cx.tcx.hir_body(closure.body);
|
||||
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
|
||||
},
|
||||
"then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub(super) fn check(
|
|||
})
|
||||
},
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
let closure_body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
|
||||
match &closure_expr.kind {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(
|
|||
let self_snippet = snippet(cx, recv.span, "..");
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind
|
||||
&& let arg_snippet = snippet(cx, fn_decl_span, "..")
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let Some((func, [arg_char])) = reduce_unit_expression(body.value)
|
||||
&& let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id))
|
||||
&& Some(id) == cx.tcx.lang_items().option_some_variant()
|
||||
|
|
|
|||
|
|
@ -58,8 +58,7 @@ pub(super) fn check<'tcx>(
|
|||
unwrap_or_span: unwrap_arg.span,
|
||||
};
|
||||
|
||||
let map = cx.tcx.hir();
|
||||
let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id));
|
||||
let body = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id));
|
||||
|
||||
// Visit the body, and return if we've found a reference
|
||||
if reference_visitor.visit_body(body).is_break() {
|
||||
|
|
@ -143,8 +142,8 @@ impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> {
|
|||
walk_path(self, path);
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +173,7 @@ impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> {
|
|||
rustc_hir::intravisit::walk_expr(self, expr)
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ pub(super) fn check<'tcx>(
|
|||
|
||||
fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body = cx.tcx.hir_body(body);
|
||||
|
||||
if body.params.is_empty()
|
||||
&& let hir::Expr { kind, .. } = &body.value
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::paths::STDIN;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::for_each_local_use_after_expr;
|
||||
use clippy_utils::{get_parent_expr, match_def_path};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
|
|
@ -34,7 +33,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
|
|||
|
||||
pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
|
||||
if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
|
||||
&& match_def_path(cx, recv_adt.did(), &STDIN)
|
||||
&& cx.tcx.is_diagnostic_item(sym::Stdin, recv_adt.did())
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
|
||||
&& let Res::Local(local_id) = path.res
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
|
|||
// We check that it is mapped as `Some`.
|
||||
&& is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome)
|
||||
&& let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
// And finally we check that we return a `None` in the "else case".
|
||||
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
|
|||
};
|
||||
|
||||
let closure_arg = fn_decl.inputs[0];
|
||||
let closure_expr = peel_blocks(cx.tcx.hir().body(body).value);
|
||||
let closure_expr = peel_blocks(cx.tcx.hir_body(body).value);
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let arg_snip = snippet_with_applicability(cx, closure_arg.span, "_", &mut applicability);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
|
|||
let mut applicability = Applicability::MachineApplicable;
|
||||
let any_search_snippet = if search_method == "find"
|
||||
&& let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
|
||||
&& let closure_body = cx.tcx.hir().body(body)
|
||||
&& let closure_body = cx.tcx.hir_body(body)
|
||||
&& let Some(closure_arg) = closure_body.params.first()
|
||||
{
|
||||
if let PatKind::Ref(..) = closure_arg.pat.kind {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use super::SUSPICIOUS_MAP;
|
|||
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
|
||||
if is_trait_method(cx, count_recv, sym::Iterator)
|
||||
&& let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind
|
||||
&& let closure_body = cx.tcx.hir().body(closure.body)
|
||||
&& let closure_body = cx.tcx.hir_body(closure.body)
|
||||
&& !cx.typeck_results().expr_ty(closure_body.value).is_unit()
|
||||
{
|
||||
if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::UNBUFFERED_BYTES;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_trait_def_id, is_trait_method, paths};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
|
@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
|||
if is_trait_method(cx, expr, sym::IoRead) {
|
||||
// Retrieve the DefId of the BufRead trait
|
||||
// FIXME: add a diagnostic item for `BufRead`
|
||||
let Some(buf_read) = get_trait_def_id(cx.tcx, &paths::BUF_READ) else {
|
||||
let Some(buf_read) = cx.tcx.get_diagnostic_item(sym::IoBufRead) else {
|
||||
return;
|
||||
};
|
||||
// And the implementor of the trait is not buffered
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
|
|||
}
|
||||
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body = cx.tcx.hir_body(body);
|
||||
let arg_id = body.params[0].pat.hir_id;
|
||||
let mutates_arg = mutated_variables(body.value, cx).is_none_or(|used_mutably| used_mutably.contains(&arg_id));
|
||||
let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ fn check_fold_with_op(
|
|||
) {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind
|
||||
// Extract the body of the closure passed to fold
|
||||
&& let closure_body = cx.tcx.hir().body(body)
|
||||
&& let closure_body = cx.tcx.hir_body(body)
|
||||
&& let closure_expr = peel_blocks(closure_body.value)
|
||||
|
||||
// Check if the closure body is of the form `acc <op> some_expr(x)`
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
|
|||
|
||||
if is_option || is_result || is_bool {
|
||||
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
|
||||
let body = cx.tcx.hir().body(body);
|
||||
let body = cx.tcx.hir_body(body);
|
||||
let body_expr = &body.value;
|
||||
|
||||
if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
|
||||
|
|
|
|||
|
|
@ -98,10 +98,7 @@ pub(super) fn check(
|
|||
]),
|
||||
("None", "unwrap_or_else", _) => match args[0].kind {
|
||||
hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
|
||||
(
|
||||
expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
|
||||
String::new(),
|
||||
),
|
||||
(expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()),
|
||||
(expr.span.with_lo(args[0].span.hi()), String::new()),
|
||||
]),
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ pub(super) fn check<'a>(
|
|||
let ext_def_span = def.span.until(map.span);
|
||||
|
||||
let (sugg, method, applicability) = if let ExprKind::Closure(map_closure) = map.kind
|
||||
&& let closure_body = cx.tcx.hir().body(map_closure.body)
|
||||
&& let closure_body = cx.tcx.hir_body(map_closure.body)
|
||||
&& let closure_body_value = closure_body.value.peel_blocks()
|
||||
&& let ExprKind::Binary(op, l, r) = closure_body_value.kind
|
||||
&& let Some(param) = closure_body.params.first()
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
|
|||
// lint if the caller of `map_or_else()` is a `Result`
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
|
||||
&& let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
|
||||
&& let body = cx.tcx.hir().body(body)
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let Some(first_param) = body.params.first()
|
||||
{
|
||||
let body_expr = peel_blocks(body.value);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
|
|||
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
|
||||
&& cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
|
||||
&& let ExprKind::Closure(&Closure { body, .. }) = arg.kind
|
||||
&& let closure_body = cx.tcx.hir().body(body)
|
||||
&& let closure_body = cx.tcx.hir_body(body)
|
||||
&& let &[
|
||||
Param {
|
||||
pat:
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
|||
if has_lifetime(output_ty) && has_lifetime(ty) {
|
||||
return false;
|
||||
}
|
||||
let body = cx.tcx.hir().body(*body_id);
|
||||
let body = cx.tcx.hir_body(*body_id);
|
||||
let body_expr = &body.value;
|
||||
let mut count = 0;
|
||||
return find_all_ret_expressions(cx, body_expr, |_| {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
|
|||
&& is_trait_method(cx, call_expr, sym::Iterator)
|
||||
// And the map argument is a closure
|
||||
&& let ExprKind::Closure(closure) = closure_arg.kind
|
||||
&& let closure_body = cx.tcx.hir().body(closure.body)
|
||||
&& let closure_body = cx.tcx.hir_body(closure.body)
|
||||
// And that closure has one argument ...
|
||||
&& let [closure_param] = closure_body.params
|
||||
// .. which is a tuple of 2 elements
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
|
|||
match arg.kind {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. })
|
||||
// If it's a closure, we need to check what is called.
|
||||
if let closure_body = cx.tcx.hir().body(body)
|
||||
if let closure_body = cx.tcx.hir_body(body)
|
||||
&& let [param] = closure_body.params
|
||||
&& let hir::PatKind::Binding(_, local_id, ..) = strip_pat_refs(param.pat).kind =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
|
|||
impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
|
||||
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
|
|
@ -12,7 +13,6 @@ use rustc_middle::ty;
|
|||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -183,11 +183,11 @@ fn already_const(header: hir::FnHeader) -> bool {
|
|||
header.constness == Constness::Const
|
||||
}
|
||||
|
||||
fn could_be_const_with_abi(msrv: &Msrv, abi: Abi) -> bool {
|
||||
fn could_be_const_with_abi(msrv: &Msrv, abi: ExternAbi) -> bool {
|
||||
match abi {
|
||||
Abi::Rust => true,
|
||||
ExternAbi::Rust => true,
|
||||
// `const extern "C"` was stabilized after 1.62.0
|
||||
Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN),
|
||||
ExternAbi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN),
|
||||
// Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
|
||||
_ => msrv.meets(msrvs::CONST_EXTERN_FN),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,8 +213,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
|
|||
&& !item.span.from_expansion()
|
||||
// find `Debug::fmt` function
|
||||
&& let Some(fmt_item) = items.iter().find(|i| i.ident.name == sym::fmt)
|
||||
&& let ImplItem { kind: ImplItemKind::Fn(_, body_id), .. } = cx.tcx.hir().impl_item(fmt_item.id)
|
||||
&& let body = cx.tcx.hir().body(*body_id)
|
||||
&& let ImplItem { kind: ImplItemKind::Fn(_, body_id), .. } = cx.tcx.hir_impl_item(fmt_item.id)
|
||||
&& let body = cx.tcx.hir_body(*body_id)
|
||||
&& let ExprKind::Block(block, _) = body.value.kind
|
||||
// inspect `self`
|
||||
&& let self_ty = cx.tcx.type_of(self_path_did).skip_binder().peel_refs()
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
|
|||
// note: we need to check if the trait is exported so we can't use
|
||||
// `LateLintPass::check_trait_item` here.
|
||||
for tit in trait_items {
|
||||
let tit_ = cx.tcx.hir().trait_item(tit.id);
|
||||
let tit_ = cx.tcx.hir_trait_item(tit.id);
|
||||
match tit_.kind {
|
||||
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
|
||||
hir::TraitItemKind::Fn(..) => {
|
||||
|
|
@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
|
|||
// trait method with default body needs inline in case
|
||||
// an impl is not provided
|
||||
let desc = "a default trait method";
|
||||
let item = cx.tcx.hir().trait_item(tit.id);
|
||||
let item = cx.tcx.hir_trait_item(tit.id);
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
check_missing_inline_attrs(cx, attrs, item.span, desc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ fn collect_unsafe_exprs<'tcx>(
|
|||
unsafe_ops.push(("access of a mutable static occurs here", expr.span));
|
||||
},
|
||||
|
||||
ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => {
|
||||
ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_raw_ptr() => {
|
||||
unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
|
|||
walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.cx.tcx
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue