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