1use std::iter;
2
3use rustc_ast::util::{classify, parser};
4use rustc_ast::{self as ast, ExprKind, FnRetTy, HasAttrs as _, StmtKind};
5use rustc_data_structures::fx::FxHashMap;
6use rustc_errors::{MultiSpan, pluralize};
7use rustc_hir::def::{DefKind, Res};
8use rustc_hir::def_id::DefId;
9use rustc_hir::{self as hir, LangItem, find_attr};
10use rustc_infer::traits::util::elaborate;
11use rustc_middle::ty::{self, Ty, adjustment};
12use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
13use rustc_span::edition::Edition::Edition2015;
14use rustc_span::{BytePos, Span, Symbol, kw, sym};
15use tracing::instrument;
16
17use crate::lints::{
18 PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
19 UnusedAllocationMutDiag, UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion,
20 UnusedDelim, UnusedDelimSuggestion, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
21 UnusedResult,
22};
23use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Lint, LintContext};
24
25#[doc =
r" The `unused_must_use` lint detects unused result of a type flagged as"]
#[doc = r" `#[must_use]`."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" fn returns_result() -> Result<(), ()> {"]
#[doc = r" Ok(())"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" returns_result();"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" The `#[must_use]` attribute is an indicator that it is a mistake to"]
#[doc = r" ignore the value. See [the reference] for more details."]
#[doc = r""]
#[doc =
r" [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"]
pub static UNUSED_MUST_USE: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_MUST_USE",
default_level: ::rustc_lint_defs::Warn,
desc: "unused result of a type flagged as `#[must_use]`",
is_externally_loaded: false,
report_in_external_macro: true,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
26 pub UNUSED_MUST_USE,
50 Warn,
51 "unused result of a type flagged as `#[must_use]`",
52 report_in_external_macro
53}
54
55#[doc = r" The `unused_results` lint checks for the unused result of an"]
#[doc = r" expression in a statement."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" #![deny(unused_results)]"]
#[doc = r" fn foo<T>() -> T { panic!() }"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" foo::<usize>();"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" Ignoring the return value of a function may indicate a mistake. In"]
#[doc =
r" cases were it is almost certain that the result should be used, it is"]
#[doc =
r" recommended to annotate the function with the [`must_use` attribute]."]
#[doc =
r" Failure to use such a return value will trigger the [`unused_must_use`"]
#[doc = r" lint] which is warn-by-default. The `unused_results` lint is"]
#[doc = r" essentially the same, but triggers for *all* return values."]
#[doc = r""]
#[doc =
r#" This lint is "allow" by default because it can be noisy, and may not be"#]
#[doc =
r" an actual problem. For example, calling the `remove` method of a `Vec`"]
#[doc =
r" or `HashMap` returns the previous value, which you may not care about."]
#[doc =
r" Using this lint would require explicitly ignoring or discarding such"]
#[doc = r" values."]
#[doc = r""]
#[doc =
r" [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"]
#[doc = r" [`unused_must_use` lint]: warn-by-default.html#unused-must-use"]
pub static UNUSED_RESULTS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_RESULTS",
default_level: ::rustc_lint_defs::Allow,
desc: "unused result of an expression in a statement",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
56 pub UNUSED_RESULTS,
90 Allow,
91 "unused result of an expression in a statement"
92}
93
94pub struct UnusedResults;
#[automatically_derived]
impl ::core::marker::Copy for UnusedResults { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnusedResults { }
#[automatically_derived]
impl ::core::clone::Clone for UnusedResults {
#[inline]
fn clone(&self) -> UnusedResults { *self }
}
impl ::rustc_lint_defs::LintPass for UnusedResults {
fn name(&self) -> &'static str { "UnusedResults" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_MUST_USE, UNUSED_RESULTS]))
}
}
impl UnusedResults {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_MUST_USE, UNUSED_RESULTS]))
}
}declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
95
96impl<'tcx> LateLintPass<'tcx> for UnusedResults {
97 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
98 let hir::StmtKind::Semi(mut expr) = s.kind else {
99 return;
100 };
101
102 let mut expr_is_from_block = false;
103 while let hir::ExprKind::Block(blk, ..) = expr.kind
104 && let hir::Block { expr: Some(e), .. } = blk
105 {
106 expr = e;
107 expr_is_from_block = true;
108 }
109
110 if let hir::ExprKind::Ret(..) = expr.kind {
111 return;
112 }
113
114 if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
115 && let ty = cx.typeck_results().expr_ty(await_expr)
116 && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
117 && cx.tcx.ty_is_opaque_future(ty)
118 && let async_fn_def_id = cx.tcx.parent(*future_def_id)
119 && #[allow(non_exhaustive_omitted_patterns)] match cx.tcx.def_kind(async_fn_def_id)
{
DefKind::Fn | DefKind::AssocFn => true,
_ => false,
}matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn)
120 && cx.tcx.asyncness(async_fn_def_id).is_async()
122 && check_must_use_def(
123 cx,
124 async_fn_def_id,
125 expr.span,
126 "output of future returned by ",
127 "",
128 expr_is_from_block,
129 )
130 {
131 return;
134 }
135
136 let ty = cx.typeck_results().expr_ty(expr);
137
138 let must_use_result = is_ty_must_use(cx, ty, expr, expr.span);
139 let type_lint_emitted_or_suppressed = match must_use_result {
140 Some(path) => {
141 emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
142 true
143 }
144 None => false,
145 };
146
147 let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block);
148
149 if !fn_warned && type_lint_emitted_or_suppressed {
150 return;
153 }
154
155 let must_use_op = match expr.kind {
156 hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
160 hir::BinOpKind::Eq
161 | hir::BinOpKind::Lt
162 | hir::BinOpKind::Le
163 | hir::BinOpKind::Ne
164 | hir::BinOpKind::Ge
165 | hir::BinOpKind::Gt => Some("comparison"),
166 hir::BinOpKind::Add
167 | hir::BinOpKind::Sub
168 | hir::BinOpKind::Div
169 | hir::BinOpKind::Mul
170 | hir::BinOpKind::Rem => Some("arithmetic operation"),
171 hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
172 hir::BinOpKind::BitXor
173 | hir::BinOpKind::BitAnd
174 | hir::BinOpKind::BitOr
175 | hir::BinOpKind::Shl
176 | hir::BinOpKind::Shr => Some("bitwise operation"),
177 },
178 hir::ExprKind::AddrOf(..) => Some("borrow"),
179 hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"),
180 hir::ExprKind::Unary(..) => Some("unary operation"),
181 hir::ExprKind::ConstBlock(block) => {
183 let body = cx.tcx.hir_body(block.body);
184 if let hir::ExprKind::Block(block, _) = body.value.kind
185 && let Some(expr) = block.expr
186 && let hir::ExprKind::OffsetOf(..) = expr.kind
187 {
188 Some("`offset_of` call")
189 } else {
190 None
191 }
192 }
193 _ => None,
194 };
195
196 let mut op_warned = false;
197
198 if let Some(must_use_op) = must_use_op {
199 let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
200 cx.emit_span_lint(
201 UNUSED_MUST_USE,
202 expr.span,
203 UnusedOp {
204 op: must_use_op,
205 label: expr.span,
206 suggestion: if expr_is_from_block {
207 UnusedOpSuggestion::BlockTailExpr {
208 before_span: span.shrink_to_lo(),
209 after_span: span.shrink_to_hi(),
210 }
211 } else {
212 UnusedOpSuggestion::NormalExpr { span: span.shrink_to_lo() }
213 },
214 },
215 );
216 op_warned = true;
217 }
218
219 if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) {
220 cx.emit_span_lint(UNUSED_RESULTS, s.span, UnusedResult { ty });
221 }
222
223 fn check_fn_must_use(
224 cx: &LateContext<'_>,
225 expr: &hir::Expr<'_>,
226 expr_is_from_block: bool,
227 ) -> bool {
228 let maybe_def_id = match expr.kind {
229 hir::ExprKind::Call(callee, _) => {
230 match callee.kind {
231 hir::ExprKind::Path(ref qpath) => {
232 match cx.qpath_res(qpath, callee.hir_id) {
233 Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
234 _ => None,
237 }
238 }
239 _ => None,
240 }
241 }
242 hir::ExprKind::MethodCall(..) => {
243 cx.typeck_results().type_dependent_def_id(expr.hir_id)
244 }
245 _ => None,
246 };
247 if let Some(def_id) = maybe_def_id {
248 check_must_use_def(
249 cx,
250 def_id,
251 expr.span,
252 "return value of ",
253 "",
254 expr_is_from_block,
255 )
256 } else {
257 false
258 }
259 }
260
261 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for MustUsePath {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MustUsePath::Suppressed =>
::core::fmt::Formatter::write_str(f, "Suppressed"),
MustUsePath::Def(__self_0, __self_1, __self_2) =>
::core::fmt::Formatter::debug_tuple_field3_finish(f, "Def",
__self_0, __self_1, &__self_2),
MustUsePath::Boxed(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Boxed",
&__self_0),
MustUsePath::Pinned(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Pinned",
&__self_0),
MustUsePath::Opaque(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Opaque",
&__self_0),
MustUsePath::TraitObject(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"TraitObject", &__self_0),
MustUsePath::TupleElement(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"TupleElement", &__self_0),
MustUsePath::Array(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Array",
__self_0, &__self_1),
MustUsePath::Closure(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Closure", &__self_0),
MustUsePath::Coroutine(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Coroutine", &__self_0),
}
}
}Debug)]
263 enum MustUsePath {
264 Suppressed,
266 Def(Span, DefId, Option<Symbol>),
268 Boxed(Box<Self>),
269 Pinned(Box<Self>),
270 Opaque(Box<Self>),
271 TraitObject(Box<Self>),
272 TupleElement(Vec<(usize, Self)>),
273 Array(Box<Self>, u64),
274 Closure(Span),
276 Coroutine(Span),
278 }
279
280 x;#[instrument(skip(cx, expr), level = "debug", ret)]
281 fn is_ty_must_use<'tcx>(
282 cx: &LateContext<'tcx>,
283 ty: Ty<'tcx>,
284 expr: &hir::Expr<'_>,
285 span: Span,
286 ) -> Option<MustUsePath> {
287 if ty.is_unit() {
288 return Some(MustUsePath::Suppressed);
289 }
290 let parent_mod_did = cx.tcx.parent_module(expr.hir_id).to_def_id();
291 let is_uninhabited =
292 |t: Ty<'tcx>| !t.is_inhabited_from(cx.tcx, parent_mod_did, cx.typing_env());
293 if is_uninhabited(ty) {
294 return Some(MustUsePath::Suppressed);
295 }
296
297 match *ty.kind() {
298 ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => {
299 is_ty_must_use(cx, boxed, expr, span)
300 .map(|inner| MustUsePath::Boxed(Box::new(inner)))
301 }
302 ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => {
303 let pinned_ty = args.type_at(0);
304 is_ty_must_use(cx, pinned_ty, expr, span)
305 .map(|inner| MustUsePath::Pinned(Box::new(inner)))
306 }
307 ty::Adt(def, args)
309 if cx.tcx.is_diagnostic_item(sym::Result, def.did())
310 && args.type_at(0).is_unit()
311 && is_uninhabited(args.type_at(1)) =>
312 {
313 Some(MustUsePath::Suppressed)
314 }
315 ty::Adt(def, args)
317 if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
318 && args.type_at(1).is_unit()
319 && is_uninhabited(args.type_at(0)) =>
320 {
321 Some(MustUsePath::Suppressed)
322 }
323 ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
324 ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
325 elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied())
326 .filter_only_self()
328 .find_map(|(pred, _span)| {
329 if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
331 pred.kind().skip_binder()
332 {
333 let def_id = poly_trait_predicate.trait_ref.def_id;
334
335 is_def_must_use(cx, def_id, span)
336 } else {
337 None
338 }
339 })
340 .map(|inner| MustUsePath::Opaque(Box::new(inner)))
341 }
342 ty::Dynamic(binders, _) => binders.iter().find_map(|predicate| {
343 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
344 {
345 let def_id = trait_ref.def_id;
346 is_def_must_use(cx, def_id, span)
347 .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
348 } else {
349 None
350 }
351 }),
352 ty::Tuple(tys) => {
353 let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
354 debug_assert_eq!(elem_exprs.len(), tys.len());
355 elem_exprs
356 } else {
357 &[]
358 };
359
360 let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr));
362
363 let nested_must_use = tys
364 .iter()
365 .zip(elem_exprs)
366 .enumerate()
367 .filter_map(|(i, (ty, expr))| {
368 is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path))
369 })
370 .collect::<Vec<_>>();
371
372 if !nested_must_use.is_empty() {
373 Some(MustUsePath::TupleElement(nested_must_use))
374 } else {
375 None
376 }
377 }
378 ty::Array(ty, len) => match len.try_to_target_usize(cx.tcx) {
379 Some(0) | None => None,
381 Some(len) => is_ty_must_use(cx, ty, expr, span)
383 .map(|inner| MustUsePath::Array(Box::new(inner), len)),
384 },
385 ty::Closure(..) | ty::CoroutineClosure(..) => Some(MustUsePath::Closure(span)),
386 ty::Coroutine(def_id, ..) => {
387 let must_use = if cx.tcx.coroutine_is_async(def_id) {
389 let def_id = cx.tcx.lang_items().future_trait()?;
390 is_def_must_use(cx, def_id, span)
391 .map(|inner| MustUsePath::Opaque(Box::new(inner)))
392 } else {
393 None
394 };
395 must_use.or(Some(MustUsePath::Coroutine(span)))
396 }
397 _ => None,
398 }
399 }
400
401 fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> {
402 if let Some(reason) = {
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(def_id) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(MustUse { reason, .. }) => {
break 'done Some(reason);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}find_attr!(
403 cx.tcx, def_id,
404 MustUse { reason, .. } => reason
405 ) {
406 Some(MustUsePath::Def(span, def_id, *reason))
408 } else {
409 None
410 }
411 }
412
413 fn check_must_use_def(
416 cx: &LateContext<'_>,
417 def_id: DefId,
418 span: Span,
419 descr_pre_path: &str,
420 descr_post_path: &str,
421 expr_is_from_block: bool,
422 ) -> bool {
423 is_def_must_use(cx, def_id, span)
424 .map(|must_use_path| {
425 emit_must_use_untranslated(
426 cx,
427 &must_use_path,
428 descr_pre_path,
429 descr_post_path,
430 1,
431 false,
432 expr_is_from_block,
433 )
434 })
435 .is_some()
436 }
437
438 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("emit_must_use_untranslated",
"rustc_lint::unused", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/unused.rs"),
::tracing_core::__macro_support::Option::Some(438u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::unused"),
::tracing_core::field::FieldSet::new(&["path", "descr_pre",
"descr_post", "plural_len", "is_inner",
"expr_is_from_block"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&path)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&descr_pre as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&descr_post as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&plural_len as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&is_inner as
&dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&expr_is_from_block
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let plural_suffix = if plural_len == 1 { "" } else { "s" };
match path {
MustUsePath::Suppressed => {}
MustUsePath::Boxed(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}boxed ", descr_pre))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::Pinned(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}pinned ", descr_pre))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::Opaque(path) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}implementer{1} of ",
descr_pre, plural_suffix))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::TraitObject(path) => {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" trait object{0}{1}",
plural_suffix, descr_post))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
MustUsePath::TupleElement(elems) => {
for (index, path) in elems {
let descr_post =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" in tuple element {0}",
index))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len, true, expr_is_from_block);
}
}
MustUsePath::Array(path, len) => {
let descr_pre =
&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}array{1} of ",
descr_pre, plural_suffix))
});
emit_must_use_untranslated(cx, path, descr_pre, descr_post,
plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
true, expr_is_from_block);
}
MustUsePath::Closure(span) => {
cx.emit_span_lint(UNUSED_MUST_USE, *span,
UnusedClosure {
count: plural_len,
pre: descr_pre,
post: descr_post,
});
}
MustUsePath::Coroutine(span) => {
cx.emit_span_lint(UNUSED_MUST_USE, *span,
UnusedCoroutine {
count: plural_len,
pre: descr_pre,
post: descr_post,
});
}
MustUsePath::Def(span, def_id, reason) => {
let ancenstor_span =
span.find_ancestor_not_from_macro().unwrap_or(*span);
let is_redundant_let_ignore =
cx.sess().source_map().span_to_prev_source(ancenstor_span).ok().map(|prev|
prev.trim_end().ends_with("let _ =")).unwrap_or(false);
let suggestion_span =
if is_redundant_let_ignore {
*span
} else { ancenstor_span };
cx.emit_span_lint(UNUSED_MUST_USE, ancenstor_span,
UnusedDef {
pre: descr_pre,
post: descr_post,
cx,
def_id: *def_id,
note: *reason,
suggestion: (!is_inner).then_some(if expr_is_from_block {
UnusedDefSuggestion::BlockTailExpr {
before_span: suggestion_span.shrink_to_lo(),
after_span: suggestion_span.shrink_to_hi(),
}
} else {
UnusedDefSuggestion::NormalExpr {
span: suggestion_span.shrink_to_lo(),
}
}),
});
}
}
}
}
}#[instrument(skip(cx), level = "debug")]
439 fn emit_must_use_untranslated(
440 cx: &LateContext<'_>,
441 path: &MustUsePath,
442 descr_pre: &str,
443 descr_post: &str,
444 plural_len: usize,
445 is_inner: bool,
446 expr_is_from_block: bool,
447 ) {
448 let plural_suffix = pluralize!(plural_len);
449
450 match path {
451 MustUsePath::Suppressed => {}
452 MustUsePath::Boxed(path) => {
453 let descr_pre = &format!("{descr_pre}boxed ");
454 emit_must_use_untranslated(
455 cx,
456 path,
457 descr_pre,
458 descr_post,
459 plural_len,
460 true,
461 expr_is_from_block,
462 );
463 }
464 MustUsePath::Pinned(path) => {
465 let descr_pre = &format!("{descr_pre}pinned ");
466 emit_must_use_untranslated(
467 cx,
468 path,
469 descr_pre,
470 descr_post,
471 plural_len,
472 true,
473 expr_is_from_block,
474 );
475 }
476 MustUsePath::Opaque(path) => {
477 let descr_pre = &format!("{descr_pre}implementer{plural_suffix} of ");
478 emit_must_use_untranslated(
479 cx,
480 path,
481 descr_pre,
482 descr_post,
483 plural_len,
484 true,
485 expr_is_from_block,
486 );
487 }
488 MustUsePath::TraitObject(path) => {
489 let descr_post = &format!(" trait object{plural_suffix}{descr_post}");
490 emit_must_use_untranslated(
491 cx,
492 path,
493 descr_pre,
494 descr_post,
495 plural_len,
496 true,
497 expr_is_from_block,
498 );
499 }
500 MustUsePath::TupleElement(elems) => {
501 for (index, path) in elems {
502 let descr_post = &format!(" in tuple element {index}");
503 emit_must_use_untranslated(
504 cx,
505 path,
506 descr_pre,
507 descr_post,
508 plural_len,
509 true,
510 expr_is_from_block,
511 );
512 }
513 }
514 MustUsePath::Array(path, len) => {
515 let descr_pre = &format!("{descr_pre}array{plural_suffix} of ");
516 emit_must_use_untranslated(
517 cx,
518 path,
519 descr_pre,
520 descr_post,
521 plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)),
522 true,
523 expr_is_from_block,
524 );
525 }
526 MustUsePath::Closure(span) => {
527 cx.emit_span_lint(
528 UNUSED_MUST_USE,
529 *span,
530 UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
531 );
532 }
533 MustUsePath::Coroutine(span) => {
534 cx.emit_span_lint(
535 UNUSED_MUST_USE,
536 *span,
537 UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post },
538 );
539 }
540 MustUsePath::Def(span, def_id, reason) => {
541 let ancenstor_span = span.find_ancestor_not_from_macro().unwrap_or(*span);
542 let is_redundant_let_ignore = cx
543 .sess()
544 .source_map()
545 .span_to_prev_source(ancenstor_span)
546 .ok()
547 .map(|prev| prev.trim_end().ends_with("let _ ="))
548 .unwrap_or(false);
549 let suggestion_span =
550 if is_redundant_let_ignore { *span } else { ancenstor_span };
551 cx.emit_span_lint(
552 UNUSED_MUST_USE,
553 ancenstor_span,
554 UnusedDef {
555 pre: descr_pre,
556 post: descr_post,
557 cx,
558 def_id: *def_id,
559 note: *reason,
560 suggestion: (!is_inner).then_some(if expr_is_from_block {
561 UnusedDefSuggestion::BlockTailExpr {
562 before_span: suggestion_span.shrink_to_lo(),
563 after_span: suggestion_span.shrink_to_hi(),
564 }
565 } else {
566 UnusedDefSuggestion::NormalExpr {
567 span: suggestion_span.shrink_to_lo(),
568 }
569 }),
570 },
571 );
572 }
573 }
574 }
575 }
576}
577
578#[doc =
r" The `path_statements` lint detects path statements with no effect."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" let x = 42;"]
#[doc = r""]
#[doc = r" x;"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" It is usually a mistake to have a statement that has no effect."]
pub static PATH_STATEMENTS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "PATH_STATEMENTS",
default_level: ::rustc_lint_defs::Warn,
desc: "path statements with no effect",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
579 pub PATH_STATEMENTS,
595 Warn,
596 "path statements with no effect"
597}
598
599pub struct PathStatements;
#[automatically_derived]
impl ::core::marker::Copy for PathStatements { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PathStatements { }
#[automatically_derived]
impl ::core::clone::Clone for PathStatements {
#[inline]
fn clone(&self) -> PathStatements { *self }
}
impl ::rustc_lint_defs::LintPass for PathStatements {
fn name(&self) -> &'static str { "PathStatements" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[PATH_STATEMENTS]))
}
}
impl PathStatements {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[PATH_STATEMENTS]))
}
}declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
600
601impl<'tcx> LateLintPass<'tcx> for PathStatements {
602 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
603 if let hir::StmtKind::Semi(expr) = s.kind
604 && let hir::ExprKind::Path(_) = expr.kind
605 {
606 let ty = cx.typeck_results().expr_ty(expr);
607 if ty.needs_drop(cx.tcx, cx.typing_env()) {
608 let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
609 PathStatementDropSub::Suggestion { span: s.span, snippet }
610 } else {
611 PathStatementDropSub::Help { span: s.span }
612 };
613 cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
614 } else {
615 cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
616 }
617 }
618 }
619}
620
621#[derive(#[automatically_derived]
impl ::core::marker::Copy for UnusedDelimsCtx { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UnusedDelimsCtx {
#[inline]
fn clone(&self) -> UnusedDelimsCtx { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for UnusedDelimsCtx {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
UnusedDelimsCtx::FunctionArg => "FunctionArg",
UnusedDelimsCtx::MethodArg => "MethodArg",
UnusedDelimsCtx::AssignedValue => "AssignedValue",
UnusedDelimsCtx::AssignedValueLetElse =>
"AssignedValueLetElse",
UnusedDelimsCtx::IfCond => "IfCond",
UnusedDelimsCtx::WhileCond => "WhileCond",
UnusedDelimsCtx::ForIterExpr => "ForIterExpr",
UnusedDelimsCtx::MatchScrutineeExpr => "MatchScrutineeExpr",
UnusedDelimsCtx::ReturnValue => "ReturnValue",
UnusedDelimsCtx::BlockRetValue => "BlockRetValue",
UnusedDelimsCtx::BreakValue => "BreakValue",
UnusedDelimsCtx::LetScrutineeExpr => "LetScrutineeExpr",
UnusedDelimsCtx::ArrayLenExpr => "ArrayLenExpr",
UnusedDelimsCtx::AnonConst => "AnonConst",
UnusedDelimsCtx::MatchArmExpr => "MatchArmExpr",
UnusedDelimsCtx::IndexExpr => "IndexExpr",
UnusedDelimsCtx::ClosureBody => "ClosureBody",
})
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for UnusedDelimsCtx {
#[inline]
fn eq(&self, other: &UnusedDelimsCtx) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UnusedDelimsCtx {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
}Eq)]
622enum UnusedDelimsCtx {
623 FunctionArg,
624 MethodArg,
625 AssignedValue,
626 AssignedValueLetElse,
627 IfCond,
628 WhileCond,
629 ForIterExpr,
630 MatchScrutineeExpr,
631 ReturnValue,
632 BlockRetValue,
633 BreakValue,
634 LetScrutineeExpr,
635 ArrayLenExpr,
636 AnonConst,
637 MatchArmExpr,
638 IndexExpr,
639 ClosureBody,
640}
641
642impl From<UnusedDelimsCtx> for &'static str {
643 fn from(ctx: UnusedDelimsCtx) -> &'static str {
644 match ctx {
645 UnusedDelimsCtx::FunctionArg => "function argument",
646 UnusedDelimsCtx::MethodArg => "method argument",
647 UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
648 "assigned value"
649 }
650 UnusedDelimsCtx::IfCond => "`if` condition",
651 UnusedDelimsCtx::WhileCond => "`while` condition",
652 UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
653 UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
654 UnusedDelimsCtx::ReturnValue => "`return` value",
655 UnusedDelimsCtx::BlockRetValue => "block return value",
656 UnusedDelimsCtx::BreakValue => "`break` value",
657 UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
658 UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
659 UnusedDelimsCtx::MatchArmExpr => "match arm expression",
660 UnusedDelimsCtx::IndexExpr => "index expression",
661 UnusedDelimsCtx::ClosureBody => "closure body",
662 }
663 }
664}
665
666trait UnusedDelimLint {
668 const DELIM_STR: &'static str;
669
670 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool;
682
683 fn lint(&self) -> &'static Lint;
685
686 fn check_unused_delims_expr(
687 &self,
688 cx: &EarlyContext<'_>,
689 value: &ast::Expr,
690 ctx: UnusedDelimsCtx,
691 followed_by_block: bool,
692 left_pos: Option<BytePos>,
693 right_pos: Option<BytePos>,
694 is_kw: bool,
695 );
696
697 fn is_expr_delims_necessary(
698 inner: &ast::Expr,
699 ctx: UnusedDelimsCtx,
700 followed_by_block: bool,
701 ) -> bool {
702 let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
703
704 if followed_by_else {
705 match inner.kind {
706 ast::ExprKind::Binary(op, ..) if op.node.is_lazy() => return true,
707 _ if classify::expr_trailing_brace(inner).is_some() => return true,
708 _ => {}
709 }
710 }
711
712 if let ast::ExprKind::Range(..) = inner.kind
714 && #[allow(non_exhaustive_omitted_patterns)] match ctx {
UnusedDelimsCtx::LetScrutineeExpr => true,
_ => false,
}matches!(ctx, UnusedDelimsCtx::LetScrutineeExpr)
715 {
716 return true;
717 }
718
719 if #[allow(non_exhaustive_omitted_patterns)] match inner.kind {
ast::ExprKind::AddrOf(ast::BorrowKind::Raw, ..) => true,
_ => false,
}matches!(inner.kind, ast::ExprKind::AddrOf(ast::BorrowKind::Raw, ..)) {
723 return true;
724 }
725
726 {
756 let mut innermost = inner;
757 loop {
758 innermost = match &innermost.kind {
759 ExprKind::Binary(_op, lhs, _rhs) => lhs,
760 ExprKind::Call(fn_, _params) => fn_,
761 ExprKind::Cast(expr, _ty) => expr,
762 ExprKind::Type(expr, _ty) => expr,
763 ExprKind::Index(base, _subscript, _) => base,
764 _ => break,
765 };
766 if !classify::expr_requires_semi_to_be_stmt(innermost) {
767 return true;
768 }
769 }
770 }
771
772 if !followed_by_block {
775 return false;
776 }
777
778 {
780 let mut innermost = inner;
781 loop {
782 innermost = match &innermost.kind {
783 ExprKind::AddrOf(_, _, expr) => expr,
784 _ => {
785 if parser::contains_exterior_struct_lit(innermost) {
786 return true;
787 } else {
788 break;
789 }
790 }
791 }
792 }
793 }
794
795 let mut innermost = inner;
796 loop {
797 innermost = match &innermost.kind {
798 ExprKind::Unary(_op, expr) => expr,
799 ExprKind::Binary(_op, _lhs, rhs) => rhs,
800 ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
801 ExprKind::Assign(_lhs, rhs, _span) => rhs,
802
803 ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true,
804
805 ExprKind::Break(_label, None) => return false,
806 ExprKind::Break(_label, Some(break_expr)) => {
807 return #[allow(non_exhaustive_omitted_patterns)] match break_expr.kind {
ExprKind::Block(..) | ExprKind::Path(..) => true,
_ => false,
}matches!(break_expr.kind, ExprKind::Block(..) | ExprKind::Path(..));
811 }
812
813 ExprKind::Range(_lhs, Some(rhs), _limits) => {
814 return #[allow(non_exhaustive_omitted_patterns)] match rhs.kind {
ExprKind::Block(..) => true,
_ => false,
}matches!(rhs.kind, ExprKind::Block(..));
815 }
816
817 _ => return parser::contains_exterior_struct_lit(inner),
818 }
819 }
820 }
821
822 fn emit_unused_delims_expr(
823 &self,
824 cx: &EarlyContext<'_>,
825 value: &ast::Expr,
826 ctx: UnusedDelimsCtx,
827 left_pos: Option<BytePos>,
828 right_pos: Option<BytePos>,
829 is_kw: bool,
830 ) {
831 let span_with_attrs = match value.kind {
832 ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => {
833 if let Some(attr_lo) = stmt.attrs().iter().map(|attr| attr.span.lo()).min() {
836 stmt.span.with_lo(attr_lo)
837 } else {
838 stmt.span
839 }
840 }
841 ast::ExprKind::Paren(ref expr) => {
842 if let Some(attr_lo) = expr.attrs.iter().map(|attr| attr.span.lo()).min() {
845 expr.span.with_lo(attr_lo)
846 } else {
847 expr.span
848 }
849 }
850 _ => return,
851 };
852 let spans = span_with_attrs
853 .find_ancestor_inside(value.span)
854 .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi())));
855 let keep_space = (
856 left_pos.is_some_and(|s| s >= value.span.lo()),
857 right_pos.is_some_and(|s| s <= value.span.hi()),
858 );
859 self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space, is_kw);
860 }
861
862 fn emit_unused_delims(
863 &self,
864 cx: &EarlyContext<'_>,
865 value_span: Span,
866 spans: Option<(Span, Span)>,
867 msg: &str,
868 keep_space: (bool, bool),
869 is_kw: bool,
870 ) {
871 let primary_span = if let Some((lo, hi)) = spans {
872 if hi.is_empty() {
873 return;
875 }
876 MultiSpan::from(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[lo, hi]))vec![lo, hi])
877 } else {
878 MultiSpan::from(value_span)
879 };
880 let suggestion = spans.map(|(lo, hi)| {
881 let sm = cx.sess().source_map();
882 let lo_replace = if (keep_space.0 || is_kw)
883 && let Ok(snip) = sm.span_to_prev_source(lo)
884 && !snip.ends_with(' ')
885 {
886 " "
887 } else if let Ok(snip) = sm.span_to_prev_source(value_span)
888 && snip.ends_with(|c: char| c.is_alphanumeric())
889 {
890 " "
891 } else {
892 ""
893 };
894
895 let hi_replace = if keep_space.1
896 && let Ok(snip) = sm.span_to_next_source(hi)
897 && !snip.starts_with(' ')
898 {
899 " "
900 } else if let Ok(snip) = sm.span_to_prev_source(value_span)
901 && snip.starts_with(|c: char| c.is_alphanumeric())
902 {
903 " "
904 } else {
905 ""
906 };
907 UnusedDelimSuggestion {
908 start_span: lo,
909 start_replace: lo_replace,
910 end_span: hi,
911 end_replace: hi_replace,
912 }
913 });
914 cx.emit_span_lint(
915 self.lint(),
916 primary_span,
917 UnusedDelim { delim: Self::DELIM_STR, item: msg, suggestion },
918 );
919 }
920
921 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
922 use rustc_ast::ExprKind::*;
923 let (value, ctx, followed_by_block, left_pos, right_pos, is_kw) = match e.kind {
924 If(ref cond, ref block, _)
926 if !#[allow(non_exhaustive_omitted_patterns)] match cond.kind {
Let(..) => true,
_ => false,
}matches!(cond.kind, Let(..)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
927 {
928 let left = e.span.lo() + rustc_span::BytePos(2);
929 let right = block.span.lo();
930 (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right), true)
931 }
932
933 While(ref cond, ref block, ..)
935 if !#[allow(non_exhaustive_omitted_patterns)] match cond.kind {
Let(..) => true,
_ => false,
}matches!(cond.kind, Let(..)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
936 {
937 let left = e.span.lo() + rustc_span::BytePos(5);
938 let right = block.span.lo();
939 (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
940 }
941
942 ForLoop { ref iter, ref body, .. } => {
943 (iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
944 }
945
946 Match(ref head, _, ast::MatchKind::Prefix)
947 if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
948 {
949 let left = e.span.lo() + rustc_span::BytePos(5);
950 (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
951 }
952
953 Ret(Some(ref value)) => {
954 let left = e.span.lo() + rustc_span::BytePos(3);
955 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true)
956 }
957
958 Break(label, Some(ref value)) => {
959 if label.is_some()
963 && #[allow(non_exhaustive_omitted_patterns)] match value.kind {
ast::ExprKind::Paren(ref inner) if
#[allow(non_exhaustive_omitted_patterns)] match inner.kind {
ast::ExprKind::Block(..) => true,
_ => false,
} => true,
_ => false,
}matches!(value.kind, ast::ExprKind::Paren(ref inner)
964 if matches!(inner.kind, ast::ExprKind::Block(..)))
965 {
966 return;
967 }
968 (value, UnusedDelimsCtx::BreakValue, false, None, None, true)
969 }
970
971 Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false),
972
973 Assign(_, ref value, _) | AssignOp(.., ref value) => {
974 (value, UnusedDelimsCtx::AssignedValue, false, None, None, false)
975 }
976 ref call_or_other => {
978 let (args_to_check, ctx) = match *call_or_other {
979 Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
980 MethodCall(ref call) => (&call.args[..], UnusedDelimsCtx::MethodArg),
981 Closure(ref closure)
982 if #[allow(non_exhaustive_omitted_patterns)] match closure.fn_decl.output {
FnRetTy::Default(_) => true,
_ => false,
}matches!(closure.fn_decl.output, FnRetTy::Default(_)) =>
983 {
984 (&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody)
985 }
986 _ => {
988 return;
989 }
990 };
991 if e.span.ctxt().outer_expn_data().call_site.from_expansion() {
996 return;
997 }
998 for arg in args_to_check {
999 self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false);
1000 }
1001 return;
1002 }
1003 };
1004 self.check_unused_delims_expr(
1005 cx,
1006 value,
1007 ctx,
1008 followed_by_block,
1009 left_pos,
1010 right_pos,
1011 is_kw,
1012 );
1013 }
1014
1015 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
1016 match s.kind {
1017 StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
1018 if let Some((init, els)) = local.kind.init_else_opt() {
1019 if els.is_some()
1020 && let ExprKind::Paren(paren) = &init.kind
1021 && !init.span.eq_ctxt(paren.span)
1022 {
1023 return;
1034 }
1035 let ctx = match els {
1036 None => UnusedDelimsCtx::AssignedValue,
1037 Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
1038 };
1039 self.check_unused_delims_expr(cx, init, ctx, false, None, None, false);
1040 }
1041 }
1042 StmtKind::Expr(ref expr) => {
1043 self.check_unused_delims_expr(
1044 cx,
1045 expr,
1046 UnusedDelimsCtx::BlockRetValue,
1047 false,
1048 None,
1049 None,
1050 false,
1051 );
1052 }
1053 _ => {}
1054 }
1055 }
1056
1057 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1058 use ast::ItemKind::*;
1059
1060 let expr = if let Const(box ast::ConstItem { rhs_kind, .. }) = &item.kind {
1061 if let Some(e) = rhs_kind.expr() { e } else { return }
1062 } else if let Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind {
1063 expr
1064 } else {
1065 return;
1066 };
1067 self.check_unused_delims_expr(
1068 cx,
1069 expr,
1070 UnusedDelimsCtx::AssignedValue,
1071 false,
1072 None,
1073 None,
1074 false,
1075 );
1076 }
1077}
1078
1079#[doc =
r" The `unused_parens` lint detects `if`, `match`, `while` and `return`"]
#[doc = r" with parentheses; they do not need them."]
#[doc = r""]
#[doc = r" ### Examples"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" if(true) {}"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" The parentheses are not needed, and should be removed. This is the"]
#[doc = r" preferred style for writing these expressions."]
pub(super) static UNUSED_PARENS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_PARENS",
default_level: ::rustc_lint_defs::Warn,
desc: "`if`, `match`, `while` and `return` do not need parentheses",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
1080 pub(super) UNUSED_PARENS,
1096 Warn,
1097 "`if`, `match`, `while` and `return` do not need parentheses"
1098}
1099
1100#[derive(#[automatically_derived]
impl ::core::default::Default for UnusedParens {
#[inline]
fn default() -> UnusedParens {
UnusedParens {
with_self_ty_parens: ::core::default::Default::default(),
parens_in_cast_in_lt: ::core::default::Default::default(),
in_no_bounds_pos: ::core::default::Default::default(),
}
}
}Default)]
1101pub(crate) struct UnusedParens {
1102 with_self_ty_parens: bool,
1103 parens_in_cast_in_lt: Vec<ast::NodeId>,
1106 in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>,
1109}
1110
1111enum NoBoundsException {
1126 None,
1128 OneBound,
1131}
1132
1133impl ::rustc_lint_defs::LintPass for UnusedParens {
fn name(&self) -> &'static str { "UnusedParens" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_PARENS]))
}
}
impl UnusedParens {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_PARENS]))
}
}impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
1134
1135impl UnusedDelimLint for UnusedParens {
1136 const DELIM_STR: &'static str = "parentheses";
1137
1138 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
1139
1140 fn lint(&self) -> &'static Lint {
1141 UNUSED_PARENS
1142 }
1143
1144 fn check_unused_delims_expr(
1145 &self,
1146 cx: &EarlyContext<'_>,
1147 value: &ast::Expr,
1148 ctx: UnusedDelimsCtx,
1149 followed_by_block: bool,
1150 left_pos: Option<BytePos>,
1151 right_pos: Option<BytePos>,
1152 is_kw: bool,
1153 ) {
1154 match value.kind {
1155 ast::ExprKind::Paren(ref inner) => {
1156 if !Self::is_expr_delims_necessary(inner, ctx, followed_by_block)
1157 && value.attrs.is_empty()
1158 && !value.span.from_expansion()
1159 && (ctx != UnusedDelimsCtx::LetScrutineeExpr
1160 || !#[allow(non_exhaustive_omitted_patterns)] match inner.kind {
ast::ExprKind::Binary(rustc_span::source_map::Spanned { node, .. }, _, _)
if node.is_lazy() => true,
_ => false,
}matches!(inner.kind, ast::ExprKind::Binary(
1161 rustc_span::source_map::Spanned { node, .. },
1162 _,
1163 _,
1164 ) if node.is_lazy()))
1165 && !((ctx == UnusedDelimsCtx::ReturnValue
1166 || ctx == UnusedDelimsCtx::BreakValue)
1167 && #[allow(non_exhaustive_omitted_patterns)] match inner.kind {
ast::ExprKind::Assign(_, _, _) => true,
_ => false,
}matches!(inner.kind, ast::ExprKind::Assign(_, _, _)))
1168 {
1169 self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
1170 }
1171 }
1172 ast::ExprKind::Let(_, ref expr, _, _) => {
1173 self.check_unused_delims_expr(
1174 cx,
1175 expr,
1176 UnusedDelimsCtx::LetScrutineeExpr,
1177 followed_by_block,
1178 None,
1179 None,
1180 false,
1181 );
1182 }
1183 _ => {}
1184 }
1185 }
1186}
1187
1188impl UnusedParens {
1189 fn check_unused_parens_pat(
1190 &self,
1191 cx: &EarlyContext<'_>,
1192 value: &ast::Pat,
1193 avoid_or: bool,
1194 avoid_mut: bool,
1195 keep_space: (bool, bool),
1196 ) {
1197 use ast::{BindingMode, PatKind};
1198
1199 if let PatKind::Paren(inner) = &value.kind {
1200 match inner.kind {
1201 PatKind::Range(..) => return,
1206 PatKind::Guard(..) => return,
1208 PatKind::Or(..) if avoid_or => return,
1210 PatKind::Ident(BindingMode::MUT, ..) if avoid_mut => {
1212 return;
1213 }
1214 _ => {}
1216 }
1217 let spans = if !value.span.from_expansion() {
1218 inner
1219 .span
1220 .find_ancestor_inside(value.span)
1221 .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
1222 } else {
1223 None
1224 };
1225 self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false);
1226 }
1227 }
1228
1229 fn cast_followed_by_lt(&self, expr: &ast::Expr) -> Option<ast::NodeId> {
1230 if let ExprKind::Binary(op, lhs, _rhs) = &expr.kind
1231 && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl)
1232 {
1233 let mut cur = lhs;
1234 while let ExprKind::Binary(_, _, rhs) = &cur.kind {
1235 cur = rhs;
1236 }
1237
1238 if let ExprKind::Cast(_, ty) = &cur.kind
1239 && let ast::TyKind::Paren(_) = &ty.kind
1240 {
1241 return Some(ty.id);
1242 }
1243 }
1244 None
1245 }
1246}
1247
1248impl EarlyLintPass for UnusedParens {
1249 #[inline]
1250 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
1251 if let Some(ty_id) = self.cast_followed_by_lt(e) {
1252 self.parens_in_cast_in_lt.push(ty_id);
1253 }
1254
1255 match e.kind {
1256 ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => {
1257 self.check_unused_parens_pat(cx, pat, false, false, (true, true));
1258 }
1259 ExprKind::If(ref cond, ref block, ref else_)
1263 if #[allow(non_exhaustive_omitted_patterns)] match cond.peel_parens().kind {
ExprKind::Let(..) => true,
_ => false,
}matches!(cond.peel_parens().kind, ExprKind::Let(..)) =>
1264 {
1265 self.check_unused_delims_expr(
1266 cx,
1267 cond.peel_parens(),
1268 UnusedDelimsCtx::LetScrutineeExpr,
1269 true,
1270 None,
1271 None,
1272 true,
1273 );
1274 for stmt in &block.stmts {
1275 <Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
1276 }
1277 if let Some(e) = else_ {
1278 <Self as UnusedDelimLint>::check_expr(self, cx, e);
1279 }
1280 return;
1281 }
1282 ExprKind::Match(ref _expr, ref arm, _) => {
1283 for a in arm {
1284 if let Some(body) = &a.body {
1285 self.check_unused_delims_expr(
1286 cx,
1287 body,
1288 UnusedDelimsCtx::MatchArmExpr,
1289 false,
1290 None,
1291 None,
1292 true,
1293 );
1294 }
1295 }
1296 }
1297 _ => {}
1298 }
1299
1300 <Self as UnusedDelimLint>::check_expr(self, cx, e)
1301 }
1302
1303 fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) {
1304 if let Some(ty_id) = self.cast_followed_by_lt(e) {
1305 let id = self
1306 .parens_in_cast_in_lt
1307 .pop()
1308 .expect("check_expr and check_expr_post must balance");
1309 match (&id, &ty_id) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::Some(format_args!("check_expr, check_ty, and check_expr_post are called, in that order, by the visitor")));
}
}
};assert_eq!(
1310 id, ty_id,
1311 "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"
1312 );
1313 }
1314 }
1315
1316 fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
1317 use ast::Mutability;
1318 use ast::PatKind::*;
1319 let keep_space = (false, false);
1320 match &p.kind {
1321 Paren(_)
1323 | Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None)
1325 | Path(..) | Err(_) => {},
1326 TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
1328 self.check_unused_parens_pat(cx, p, false, false, keep_space);
1329 },
1330 Struct(_, _, fps, _) => for f in fps {
1331 self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
1332 },
1333 Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
1335 Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
1339 }
1340 }
1341
1342 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
1343 if let StmtKind::Let(ref local) = s.kind {
1344 self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false));
1345 }
1346
1347 <Self as UnusedDelimLint>::check_stmt(self, cx, s)
1348 }
1349
1350 fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
1351 self.check_unused_parens_pat(cx, ¶m.pat, true, false, (false, false));
1352 }
1353
1354 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1355 self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
1356 }
1357
1358 fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
1359 if let ast::TyKind::Paren(_) = ty.kind
1360 && Some(&ty.id) == self.parens_in_cast_in_lt.last()
1361 {
1362 return;
1363 }
1364 match &ty.kind {
1365 ast::TyKind::Array(_, len) => {
1366 self.check_unused_delims_expr(
1367 cx,
1368 &len.value,
1369 UnusedDelimsCtx::ArrayLenExpr,
1370 false,
1371 None,
1372 None,
1373 false,
1374 );
1375 }
1376 ast::TyKind::Paren(r) => {
1377 let unused_parens = match &r.kind {
1378 ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => {
1379 match self.in_no_bounds_pos.get(&ty.id) {
1380 Some(NoBoundsException::None) => false,
1381 Some(NoBoundsException::OneBound) => bounds.len() <= 1,
1382 None => true,
1383 }
1384 }
1385 ast::TyKind::FnPtr(b) => {
1386 !self.with_self_ty_parens || b.generic_params.is_empty()
1387 }
1388 _ => true,
1389 };
1390
1391 if unused_parens {
1392 let spans = (!ty.span.from_expansion())
1393 .then(|| {
1394 r.span
1395 .find_ancestor_inside(ty.span)
1396 .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
1397 })
1398 .flatten();
1399
1400 self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
1401 }
1402
1403 self.with_self_ty_parens = false;
1404 }
1405 ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
1406 let own_constraint = self.in_no_bounds_pos.get(&ty.id);
1409 let constraint = match own_constraint {
1410 Some(NoBoundsException::None) => NoBoundsException::None,
1411 Some(NoBoundsException::OneBound) => NoBoundsException::OneBound,
1412 None => NoBoundsException::OneBound,
1413 };
1414 self.in_no_bounds_pos.insert(mut_ty.ty.id, constraint);
1415 }
1416 ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
1417 for i in 0..bounds.len() {
1418 let is_last = i == bounds.len() - 1;
1419
1420 if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
1421 let fn_with_explicit_ret_ty = if let [.., segment] =
1422 &*poly_trait_ref.trait_ref.path.segments
1423 && let Some(args) = segment.args.as_ref()
1424 && let ast::GenericArgs::Parenthesized(paren_args) = &**args
1425 && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
1426 {
1427 self.in_no_bounds_pos.insert(
1428 ret_ty.id,
1429 if is_last {
1430 NoBoundsException::OneBound
1431 } else {
1432 NoBoundsException::None
1433 },
1434 );
1435
1436 true
1437 } else {
1438 false
1439 };
1440
1441 let dyn2015_exception = cx.sess().psess.edition == Edition2015
1446 && #[allow(non_exhaustive_omitted_patterns)] match ty.kind {
ast::TyKind::TraitObject(..) => true,
_ => false,
}matches!(ty.kind, ast::TyKind::TraitObject(..))
1447 && i == 0
1448 && poly_trait_ref
1449 .trait_ref
1450 .path
1451 .segments
1452 .first()
1453 .map(|s| s.ident.name == kw::PathRoot)
1454 .unwrap_or(false);
1455
1456 if let ast::Parens::Yes = poly_trait_ref.parens
1457 && (is_last || !fn_with_explicit_ret_ty)
1458 && !dyn2015_exception
1459 {
1460 let s = poly_trait_ref.span;
1461 let spans = (!s.from_expansion()).then(|| {
1462 (
1463 s.with_hi(s.lo() + rustc_span::BytePos(1)),
1464 s.with_lo(s.hi() - rustc_span::BytePos(1)),
1465 )
1466 });
1467
1468 self.emit_unused_delims(
1469 cx,
1470 poly_trait_ref.span,
1471 spans,
1472 "type",
1473 (false, false),
1474 false,
1475 );
1476 }
1477 }
1478 }
1479 }
1480 _ => {}
1481 }
1482 }
1483
1484 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1485 <Self as UnusedDelimLint>::check_item(self, cx, item)
1486 }
1487
1488 fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
1489 self.in_no_bounds_pos.clear();
1490 }
1491
1492 fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
1493 use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
1494 if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {
1495 bounded_ty,
1496 bound_generic_params,
1497 ..
1498 }) = &pred.kind
1499 && let ast::TyKind::Paren(_) = &bounded_ty.kind
1500 && bound_generic_params.is_empty()
1501 {
1502 self.with_self_ty_parens = true;
1503 }
1504 }
1505
1506 fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) {
1507 if !!self.with_self_ty_parens {
::core::panicking::panic("assertion failed: !self.with_self_ty_parens")
};assert!(!self.with_self_ty_parens);
1508 }
1509}
1510
1511#[doc = r" The `unused_braces` lint detects unnecessary braces around an"]
#[doc = r" expression."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" if { true } {"]
#[doc = r" // ..."]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" The braces are not needed, and should be removed. This is the"]
#[doc = r" preferred style for writing these expressions."]
pub(super) static UNUSED_BRACES: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_BRACES",
default_level: ::rustc_lint_defs::Warn,
desc: "unnecessary braces around an expression",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
1512 pub(super) UNUSED_BRACES,
1530 Warn,
1531 "unnecessary braces around an expression"
1532}
1533
1534pub struct UnusedBraces;
#[automatically_derived]
impl ::core::marker::Copy for UnusedBraces { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnusedBraces { }
#[automatically_derived]
impl ::core::clone::Clone for UnusedBraces {
#[inline]
fn clone(&self) -> UnusedBraces { *self }
}
impl ::rustc_lint_defs::LintPass for UnusedBraces {
fn name(&self) -> &'static str { "UnusedBraces" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_BRACES]))
}
}
impl UnusedBraces {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_BRACES]))
}
}declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
1535
1536impl UnusedDelimLint for UnusedBraces {
1537 const DELIM_STR: &'static str = "braces";
1538
1539 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
1540
1541 fn lint(&self) -> &'static Lint {
1542 UNUSED_BRACES
1543 }
1544
1545 fn check_unused_delims_expr(
1546 &self,
1547 cx: &EarlyContext<'_>,
1548 value: &ast::Expr,
1549 ctx: UnusedDelimsCtx,
1550 followed_by_block: bool,
1551 left_pos: Option<BytePos>,
1552 right_pos: Option<BytePos>,
1553 is_kw: bool,
1554 ) {
1555 match value.kind {
1556 ast::ExprKind::Block(ref inner, None)
1557 if inner.rules == ast::BlockCheckMode::Default =>
1558 {
1559 if let [stmt] = inner.stmts.as_slice()
1584 && let ast::StmtKind::Expr(ref expr) = stmt.kind
1585 && !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
1586 && (ctx != UnusedDelimsCtx::AnonConst
1587 || (#[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ast::ExprKind::Lit(_) => true,
_ => false,
}matches!(expr.kind, ast::ExprKind::Lit(_))
1588 && !expr.span.from_expansion()))
1589 && ctx != UnusedDelimsCtx::ClosureBody
1590 && !cx.sess().source_map().is_multiline(value.span)
1591 && value.attrs.is_empty()
1592 && !value.span.from_expansion()
1593 && !inner.span.from_expansion()
1594 {
1595 self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
1596 }
1597 }
1598 ast::ExprKind::Let(_, ref expr, _, _) => {
1599 self.check_unused_delims_expr(
1600 cx,
1601 expr,
1602 UnusedDelimsCtx::LetScrutineeExpr,
1603 followed_by_block,
1604 None,
1605 None,
1606 false,
1607 );
1608 }
1609 _ => {}
1610 }
1611 }
1612}
1613
1614impl EarlyLintPass for UnusedBraces {
1615 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
1616 <Self as UnusedDelimLint>::check_stmt(self, cx, s)
1617 }
1618
1619 #[inline]
1620 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
1621 <Self as UnusedDelimLint>::check_expr(self, cx, e);
1622
1623 if let ExprKind::Repeat(_, ref anon_const) = e.kind {
1624 self.check_unused_delims_expr(
1625 cx,
1626 &anon_const.value,
1627 UnusedDelimsCtx::AnonConst,
1628 false,
1629 None,
1630 None,
1631 false,
1632 );
1633 }
1634 }
1635
1636 fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
1637 if let ast::GenericArg::Const(ct) = arg {
1638 self.check_unused_delims_expr(
1639 cx,
1640 &ct.value,
1641 UnusedDelimsCtx::AnonConst,
1642 false,
1643 None,
1644 None,
1645 false,
1646 );
1647 }
1648 }
1649
1650 fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
1651 if let Some(anon_const) = &v.disr_expr {
1652 self.check_unused_delims_expr(
1653 cx,
1654 &anon_const.value,
1655 UnusedDelimsCtx::AnonConst,
1656 false,
1657 None,
1658 None,
1659 false,
1660 );
1661 }
1662 }
1663
1664 fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
1665 match ty.kind {
1666 ast::TyKind::Array(_, ref len) => {
1667 self.check_unused_delims_expr(
1668 cx,
1669 &len.value,
1670 UnusedDelimsCtx::ArrayLenExpr,
1671 false,
1672 None,
1673 None,
1674 false,
1675 );
1676 }
1677
1678 _ => {}
1679 }
1680 }
1681
1682 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1683 <Self as UnusedDelimLint>::check_item(self, cx, item)
1684 }
1685}
1686
1687#[doc =
r" The `unused_import_braces` lint catches unnecessary braces around an"]
#[doc = r" imported item."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" #![deny(unused_import_braces)]"]
#[doc = r" use test::{A};"]
#[doc = r""]
#[doc = r" pub mod test {"]
#[doc = r" pub struct A;"]
#[doc = r" }"]
#[doc = r" # fn main() {}"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" If there is only a single item, then remove the braces (`use test::A;`"]
#[doc = r" for example)."]
#[doc = r""]
#[doc = r#" This lint is "allow" by default because it is only enforcing a"#]
#[doc = r" stylistic choice."]
static UNUSED_IMPORT_BRACES: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_IMPORT_BRACES",
default_level: ::rustc_lint_defs::Allow,
desc: "unnecessary braces around an imported item",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
1688 UNUSED_IMPORT_BRACES,
1713 Allow,
1714 "unnecessary braces around an imported item"
1715}
1716
1717pub struct UnusedImportBraces;
#[automatically_derived]
impl ::core::marker::Copy for UnusedImportBraces { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnusedImportBraces { }
#[automatically_derived]
impl ::core::clone::Clone for UnusedImportBraces {
#[inline]
fn clone(&self) -> UnusedImportBraces { *self }
}
impl ::rustc_lint_defs::LintPass for UnusedImportBraces {
fn name(&self) -> &'static str { "UnusedImportBraces" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_IMPORT_BRACES]))
}
}
impl UnusedImportBraces {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_IMPORT_BRACES]))
}
}declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
1718
1719impl UnusedImportBraces {
1720 fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
1721 if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
1722 for (tree, _) in items {
1724 self.check_use_tree(cx, tree, item);
1725 }
1726
1727 let [(tree, _)] = items.as_slice() else { return };
1729
1730 let node_name = match tree.kind {
1732 ast::UseTreeKind::Simple(rename) => {
1733 let orig_ident = tree.prefix.segments.last().unwrap().ident;
1734 if orig_ident.name == kw::SelfLower {
1735 return;
1736 }
1737 rename.unwrap_or(orig_ident).name
1738 }
1739 ast::UseTreeKind::Glob => sym::asterisk,
1740 ast::UseTreeKind::Nested { .. } => return,
1741 };
1742
1743 cx.emit_span_lint(
1744 UNUSED_IMPORT_BRACES,
1745 item.span,
1746 UnusedImportBracesDiag { node: node_name },
1747 );
1748 }
1749 }
1750}
1751
1752impl EarlyLintPass for UnusedImportBraces {
1753 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1754 if let ast::ItemKind::Use(ref use_tree) = item.kind {
1755 self.check_use_tree(cx, use_tree, item);
1756 }
1757 }
1758}
1759
1760#[doc =
r" The `unused_allocation` lint detects unnecessary allocations that can"]
#[doc = r" be eliminated."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" fn main() {"]
#[doc = r" let a = Box::new([1, 2, 3]).len();"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" When a `box` expression is immediately coerced to a reference, then"]
#[doc =
r" the allocation is unnecessary, and a reference (using `&` or `&mut`)"]
#[doc = r" should be used instead to avoid the allocation."]
pub(super) static UNUSED_ALLOCATION: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNUSED_ALLOCATION",
default_level: ::rustc_lint_defs::Warn,
desc: "detects unnecessary allocations that can be eliminated",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
1761 pub(super) UNUSED_ALLOCATION,
1780 Warn,
1781 "detects unnecessary allocations that can be eliminated"
1782}
1783
1784pub struct UnusedAllocation;
#[automatically_derived]
impl ::core::marker::Copy for UnusedAllocation { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnusedAllocation { }
#[automatically_derived]
impl ::core::clone::Clone for UnusedAllocation {
#[inline]
fn clone(&self) -> UnusedAllocation { *self }
}
impl ::rustc_lint_defs::LintPass for UnusedAllocation {
fn name(&self) -> &'static str { "UnusedAllocation" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_ALLOCATION]))
}
}
impl UnusedAllocation {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[UNUSED_ALLOCATION]))
}
}declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
1785
1786impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
1787 fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &hir::Expr<'_>) {
1788 match e.kind {
1789 hir::ExprKind::Call(path_expr, [_])
1790 if let hir::ExprKind::Path(qpath) = &path_expr.kind
1791 && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()
1792 && cx.tcx.is_diagnostic_item(sym::box_new, did) => {}
1793 _ => return,
1794 }
1795
1796 for adj in cx.typeck_results().expr_adjustments(e) {
1797 if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(m)) = adj.kind {
1798 if let ty::Ref(_, inner_ty, _) = adj.target.kind()
1799 && inner_ty.is_box()
1800 {
1801 continue;
1803 }
1804 match m {
1805 adjustment::AutoBorrowMutability::Not => {
1806 cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag);
1807 }
1808 adjustment::AutoBorrowMutability::Mut { .. } => {
1809 cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag);
1810 }
1811 };
1812 }
1813 }
1814 }
1815}