]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_lint/src/unused.rs
New upstream version 1.65.0+dfsg1
[rustc.git] / compiler / rustc_lint / src / unused.rs
CommitLineData
ba9703b0 1use crate::Lint;
dfeec247 2use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
3dfed10e 3use rustc_ast as ast;
94222f64 4use rustc_ast::util::{classify, parser};
3dfed10e 5use rustc_ast::{ExprKind, StmtKind};
064997fb 6use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
dfeec247
XL
7use rustc_hir as hir;
8use rustc_hir::def::{DefKind, Res};
9use rustc_hir::def_id::DefId;
ba9703b0
XL
10use rustc_middle::ty::adjustment;
11use rustc_middle::ty::{self, Ty};
dfeec247
XL
12use rustc_span::symbol::Symbol;
13use rustc_span::symbol::{kw, sym};
f2b60f7d 14use rustc_span::{BytePos, Span};
b039eaaf 15
b039eaaf 16declare_lint! {
1b1a35ee
XL
17 /// The `unused_must_use` lint detects unused result of a type flagged as
18 /// `#[must_use]`.
19 ///
20 /// ### Example
21 ///
22 /// ```rust
23 /// fn returns_result() -> Result<(), ()> {
24 /// Ok(())
25 /// }
26 ///
27 /// fn main() {
28 /// returns_result();
29 /// }
30 /// ```
31 ///
32 /// {{produces}}
33 ///
34 /// ### Explanation
35 ///
36 /// The `#[must_use]` attribute is an indicator that it is a mistake to
37 /// ignore the value. See [the reference] for more details.
38 ///
39 /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
b039eaaf
SL
40 pub UNUSED_MUST_USE,
41 Warn,
416331ca 42 "unused result of a type flagged as `#[must_use]`",
e74abb32 43 report_in_external_macro
b039eaaf
SL
44}
45
46declare_lint! {
1b1a35ee
XL
47 /// The `unused_results` lint checks for the unused result of an
48 /// expression in a statement.
49 ///
50 /// ### Example
51 ///
52 /// ```rust,compile_fail
53 /// #![deny(unused_results)]
54 /// fn foo<T>() -> T { panic!() }
55 ///
56 /// fn main() {
57 /// foo::<usize>();
58 /// }
59 /// ```
60 ///
61 /// {{produces}}
62 ///
63 /// ### Explanation
64 ///
65 /// Ignoring the return value of a function may indicate a mistake. In
66 /// cases were it is almost certain that the result should be used, it is
67 /// recommended to annotate the function with the [`must_use` attribute].
68 /// Failure to use such a return value will trigger the [`unused_must_use`
69 /// lint] which is warn-by-default. The `unused_results` lint is
70 /// essentially the same, but triggers for *all* return values.
71 ///
72 /// This lint is "allow" by default because it can be noisy, and may not be
73 /// an actual problem. For example, calling the `remove` method of a `Vec`
74 /// or `HashMap` returns the previous value, which you may not care about.
75 /// Using this lint would require explicitly ignoring or discarding such
76 /// values.
77 ///
78 /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
79 /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
b039eaaf
SL
80 pub UNUSED_RESULTS,
81 Allow,
82 "unused result of an expression in a statement"
83}
84
532ac7d7 85declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
b039eaaf 86
f035d41b
XL
87impl<'tcx> LateLintPass<'tcx> for UnusedResults {
88 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
e74abb32 89 let expr = match s.kind {
9fa01778 90 hir::StmtKind::Semi(ref expr) => &**expr,
c30ab7b3 91 _ => return,
b039eaaf
SL
92 };
93
e74abb32 94 if let hir::ExprKind::Ret(..) = expr.kind {
b039eaaf
SL
95 return;
96 }
97
3dfed10e 98 let ty = cx.typeck_results().expr_ty(&expr);
e1599b0c 99 let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
3b2f2976
XL
100
101 let mut fn_warned = false;
ea8adc8c 102 let mut op_warned = false;
e74abb32 103 let maybe_def_id = match expr.kind {
8faf50e0 104 hir::ExprKind::Call(ref callee, _) => {
e74abb32 105 match callee.kind {
8faf50e0 106 hir::ExprKind::Path(ref qpath) => {
f035d41b 107 match cx.qpath_res(qpath, callee.hir_id) {
ba9703b0 108 Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
48663c56 109 // `Res::Local` if it was a closure, for which we
0bf4aa26 110 // do not currently support must-use linting
dfeec247 111 _ => None,
83c7162d 112 }
dfeec247
XL
113 }
114 _ => None,
83c7162d 115 }
dfeec247 116 }
3dfed10e 117 hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
dfeec247 118 _ => None,
83c7162d 119 };
48663c56 120 if let Some(def_id) = maybe_def_id {
dc9dc135 121 fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
a1dfa0c6 122 } else if type_permits_lack_of_use {
0bf4aa26
XL
123 // We don't warn about unused unit or uninhabited types.
124 // (See https://github.com/rust-lang/rust/issues/43806 for details.)
125 return;
83c7162d 126 }
0bf4aa26 127
e74abb32 128 let must_use_op = match expr.kind {
83c7162d
XL
129 // Hardcoding operators here seemed more expedient than the
130 // refactoring that would be needed to look up the `#[must_use]`
131 // attribute which does exist on the comparison trait methods
dfeec247
XL
132 hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
133 hir::BinOpKind::Eq
134 | hir::BinOpKind::Lt
135 | hir::BinOpKind::Le
136 | hir::BinOpKind::Ne
137 | hir::BinOpKind::Ge
138 | hir::BinOpKind::Gt => Some("comparison"),
139 hir::BinOpKind::Add
140 | hir::BinOpKind::Sub
141 | hir::BinOpKind::Div
142 | hir::BinOpKind::Mul
143 | hir::BinOpKind::Rem => Some("arithmetic operation"),
144 hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
145 hir::BinOpKind::BitXor
146 | hir::BinOpKind::BitAnd
147 | hir::BinOpKind::BitOr
148 | hir::BinOpKind::Shl
149 | hir::BinOpKind::Shr => Some("bitwise operation"),
83c7162d 150 },
136023e0 151 hir::ExprKind::AddrOf(..) => Some("borrow"),
8faf50e0 152 hir::ExprKind::Unary(..) => Some("unary operation"),
dfeec247 153 _ => None,
83c7162d
XL
154 };
155
156 if let Some(must_use_op) = must_use_op {
74b04a01 157 cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
064997fb
FG
158 lint.build(fluent::lint::unused_op)
159 .set_arg("op", must_use_op)
160 .span_label(expr.span, fluent::lint::label)
161 .span_suggestion_verbose(
162 expr.span.shrink_to_lo(),
163 fluent::lint::suggestion,
164 "let _ = ",
165 Applicability::MachineApplicable,
166 )
167 .emit();
74b04a01 168 });
83c7162d 169 op_warned = true;
3b2f2976
XL
170 }
171
a1dfa0c6 172 if !(type_permits_lack_of_use || fn_warned || op_warned) {
a2a8927a 173 cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
064997fb 174 lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit();
a2a8927a 175 });
b039eaaf
SL
176 }
177
dc9dc135
XL
178 // Returns whether an error has been emitted (and thus another does not need to be later).
179 fn check_must_use_ty<'tcx>(
f035d41b 180 cx: &LateContext<'tcx>,
dc9dc135 181 ty: Ty<'tcx>,
dfeec247 182 expr: &hir::Expr<'_>,
dc9dc135
XL
183 span: Span,
184 descr_pre: &str,
185 descr_post: &str,
e1599b0c 186 plural_len: usize,
dc9dc135 187 ) -> bool {
ba9703b0
XL
188 if ty.is_unit()
189 || cx.tcx.is_ty_uninhabited_from(
190 cx.tcx.parent_module(expr.hir_id).to_def_id(),
191 ty,
192 cx.param_env,
193 )
dc9dc135
XL
194 {
195 return true;
196 }
197
60c5eb7d 198 let plural_suffix = pluralize!(plural_len);
dc9dc135 199
1b1a35ee 200 match *ty.kind() {
dc9dc135
XL
201 ty::Adt(..) if ty.is_box() => {
202 let boxed_ty = ty.boxed_ty();
203 let descr_pre = &format!("{}boxed ", descr_pre);
e1599b0c 204 check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
dc9dc135 205 }
5e7ed085 206 ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
dc9dc135
XL
207 ty::Opaque(def, _) => {
208 let mut has_emitted = false;
29967ef6 209 for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
3dfed10e 210 // We only look at the `DefId`, so it is safe to skip the binder here.
94222f64 211 if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
5869c6ff 212 predicate.kind().skip_binder()
f9f354fc 213 {
3dfed10e 214 let def_id = poly_trait_predicate.trait_ref.def_id;
dfeec247
XL
215 let descr_pre =
216 &format!("{}implementer{} of ", descr_pre, plural_suffix,);
dc9dc135
XL
217 if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
218 has_emitted = true;
219 break;
220 }
221 }
222 }
223 has_emitted
224 }
f2b60f7d 225 ty::Dynamic(binder, _, _) => {
dc9dc135 226 let mut has_emitted = false;
fc512014
XL
227 for predicate in binder.iter() {
228 if let ty::ExistentialPredicate::Trait(ref trait_ref) =
229 predicate.skip_binder()
230 {
dc9dc135 231 let def_id = trait_ref.def_id;
dfeec247
XL
232 let descr_post =
233 &format!(" trait object{}{}", plural_suffix, descr_post,);
dc9dc135
XL
234 if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
235 has_emitted = true;
236 break;
237 }
238 }
239 }
240 has_emitted
241 }
242 ty::Tuple(ref tys) => {
243 let mut has_emitted = false;
5e7ed085 244 let comps = if let hir::ExprKind::Tup(comps) = expr.kind {
dc9dc135 245 debug_assert_eq!(comps.len(), tys.len());
5e7ed085 246 comps
dc9dc135 247 } else {
5e7ed085 248 &[]
dc9dc135 249 };
5e7ed085 250 for (i, ty) in tys.iter().enumerate() {
dc9dc135 251 let descr_post = &format!(" in tuple element {}", i);
5e7ed085
FG
252 let e = comps.get(i).unwrap_or(expr);
253 let span = e.span;
254 if check_must_use_ty(cx, ty, e, span, descr_pre, descr_post, plural_len) {
dc9dc135
XL
255 has_emitted = true;
256 }
257 }
258 has_emitted
259 }
416331ca 260 ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
29967ef6
XL
261 // If the array is empty we don't lint, to avoid false positives
262 Some(0) | None => false,
dc9dc135 263 // If the array is definitely non-empty, we can do `#[must_use]` checking.
29967ef6 264 Some(n) => {
dfeec247 265 let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
e1599b0c 266 check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1)
dc9dc135 267 }
dfeec247 268 },
3dfed10e
XL
269 ty::Closure(..) => {
270 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
f2b60f7d 271 // FIXME(davidtwco): this isn't properly translatable because of the
064997fb
FG
272 // pre/post strings
273 lint.build(fluent::lint::unused_closure)
274 .set_arg("count", plural_len)
275 .set_arg("pre", descr_pre)
276 .set_arg("post", descr_post)
277 .note(fluent::lint::note)
278 .emit();
3dfed10e
XL
279 });
280 true
281 }
282 ty::Generator(..) => {
283 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
f2b60f7d 284 // FIXME(davidtwco): this isn't properly translatable because of the
064997fb
FG
285 // pre/post strings
286 lint.build(fluent::lint::unused_generator)
287 .set_arg("count", plural_len)
288 .set_arg("pre", descr_pre)
289 .set_arg("post", descr_post)
290 .note(fluent::lint::note)
291 .emit();
3dfed10e
XL
292 });
293 true
294 }
dc9dc135
XL
295 _ => false,
296 }
297 }
298
299 // Returns whether an error has been emitted (and thus another does not need to be later).
74b04a01
XL
300 // FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
301 // would make calling it a big awkward. Could also take String (so args are moved), but
302 // this would still require a copy into the format string, which would only be executed
303 // when needed.
dc9dc135 304 fn check_must_use_def(
f035d41b 305 cx: &LateContext<'_>,
a1dfa0c6 306 def_id: DefId,
dc9dc135 307 span: Span,
a1dfa0c6
XL
308 descr_pre_path: &str,
309 descr_post_path: &str,
310 ) -> bool {
04454e1e
FG
311 if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
312 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
f2b60f7d 313 // FIXME(davidtwco): this isn't properly translatable because of the pre/post
064997fb
FG
314 // strings
315 let mut err = lint.build(fluent::lint::unused_def);
316 err.set_arg("pre", descr_pre_path);
317 err.set_arg("post", descr_post_path);
318 err.set_arg("def", cx.tcx.def_path_str(def_id));
04454e1e
FG
319 // check for #[must_use = "..."]
320 if let Some(note) = attr.value_str() {
321 err.note(note.as_str());
322 }
323 err.emit();
324 });
325 true
326 } else {
327 false
b039eaaf 328 }
b039eaaf
SL
329 }
330 }
331}
332
b039eaaf 333declare_lint! {
1b1a35ee
XL
334 /// The `path_statements` lint detects path statements with no effect.
335 ///
336 /// ### Example
337 ///
338 /// ```rust
339 /// let x = 42;
340 ///
341 /// x;
342 /// ```
343 ///
344 /// {{produces}}
345 ///
346 /// ### Explanation
347 ///
348 /// It is usually a mistake to have a statement that has no effect.
b039eaaf
SL
349 pub PATH_STATEMENTS,
350 Warn,
351 "path statements with no effect"
352}
353
532ac7d7 354declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
b039eaaf 355
f035d41b
XL
356impl<'tcx> LateLintPass<'tcx> for PathStatements {
357 fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
3dfed10e 358 if let hir::StmtKind::Semi(expr) = s.kind {
e74abb32 359 if let hir::ExprKind::Path(_) = expr.kind {
74b04a01 360 cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
3dfed10e
XL
361 let ty = cx.typeck_results().expr_ty(expr);
362 if ty.needs_drop(cx.tcx, cx.param_env) {
064997fb 363 let mut lint = lint.build(fluent::lint::path_statement_drop);
3dfed10e
XL
364 if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
365 lint.span_suggestion(
366 s.span,
064997fb 367 fluent::lint::suggestion,
3dfed10e
XL
368 format!("drop({});", snippet),
369 Applicability::MachineApplicable,
370 );
371 } else {
064997fb 372 lint.span_help(s.span, fluent::lint::suggestion);
3dfed10e 373 }
5e7ed085 374 lint.emit();
3dfed10e 375 } else {
064997fb 376 lint.build(fluent::lint::path_statement_no_effect).emit();
3dfed10e 377 }
74b04a01 378 });
b039eaaf 379 }
b039eaaf
SL
380 }
381 }
382}
383
ba9703b0
XL
384#[derive(Copy, Clone, Debug, PartialEq, Eq)]
385enum UnusedDelimsCtx {
386 FunctionArg,
387 MethodArg,
388 AssignedValue,
94222f64 389 AssignedValueLetElse,
ba9703b0
XL
390 IfCond,
391 WhileCond,
392 ForIterExpr,
393 MatchScrutineeExpr,
394 ReturnValue,
395 BlockRetValue,
396 LetScrutineeExpr,
397 ArrayLenExpr,
398 AnonConst,
064997fb 399 MatchArmExpr,
b039eaaf
SL
400}
401
ba9703b0
XL
402impl From<UnusedDelimsCtx> for &'static str {
403 fn from(ctx: UnusedDelimsCtx) -> &'static str {
404 match ctx {
405 UnusedDelimsCtx::FunctionArg => "function argument",
406 UnusedDelimsCtx::MethodArg => "method argument",
94222f64
XL
407 UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
408 "assigned value"
409 }
ba9703b0
XL
410 UnusedDelimsCtx::IfCond => "`if` condition",
411 UnusedDelimsCtx::WhileCond => "`while` condition",
412 UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
413 UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
414 UnusedDelimsCtx::ReturnValue => "`return` value",
415 UnusedDelimsCtx::BlockRetValue => "block return value",
416 UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
417 UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
064997fb 418 UnusedDelimsCtx::MatchArmExpr => "match arm expression",
ba9703b0 419 }
416331ca 420 }
ba9703b0 421}
416331ca 422
ba9703b0
XL
423/// Used by both `UnusedParens` and `UnusedBraces` to prevent code duplication.
424trait UnusedDelimLint {
425 const DELIM_STR: &'static str;
426
427 /// Due to `ref` pattern, there can be a difference between using
428 /// `{ expr }` and `expr` in pattern-matching contexts. This means
429 /// that we should only lint `unused_parens` and not `unused_braces`
430 /// in this case.
431 ///
432 /// ```rust
433 /// let mut a = 7;
434 /// let ref b = { a }; // We actually borrow a copy of `a` here.
435 /// a += 1; // By mutating `a` we invalidate any borrows of `a`.
436 /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here.
437 /// ```
438 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool;
439
440 // this cannot be a constant is it refers to a static.
441 fn lint(&self) -> &'static Lint;
442
443 fn check_unused_delims_expr(
dfeec247
XL
444 &self,
445 cx: &EarlyContext<'_>,
446 value: &ast::Expr,
ba9703b0 447 ctx: UnusedDelimsCtx,
dfeec247
XL
448 followed_by_block: bool,
449 left_pos: Option<BytePos>,
450 right_pos: Option<BytePos>,
ba9703b0
XL
451 );
452
94222f64
XL
453 fn is_expr_delims_necessary(
454 inner: &ast::Expr,
455 followed_by_block: bool,
456 followed_by_else: bool,
457 ) -> bool {
458 if followed_by_else {
459 match inner.kind {
460 ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
461 _ if classify::expr_trailing_brace(inner).is_some() => return true,
462 _ => {}
463 }
464 }
465
f9f354fc
XL
466 // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
467 let lhs_needs_parens = {
468 let mut innermost = inner;
469 loop {
c295e0f8
XL
470 innermost = match &innermost.kind {
471 ExprKind::Binary(_, lhs, _rhs) => lhs,
472 ExprKind::Call(fn_, _params) => fn_,
473 ExprKind::Cast(expr, _ty) => expr,
474 ExprKind::Type(expr, _ty) => expr,
475 ExprKind::Index(base, _subscript) => base,
476 _ => break false,
477 };
478 if !classify::expr_requires_semi_to_be_stmt(innermost) {
479 break true;
f9f354fc 480 }
b039eaaf 481 }
f9f354fc
XL
482 };
483
484 lhs_needs_parens
485 || (followed_by_block
a2a8927a 486 && match &inner.kind {
3dfed10e 487 ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true,
a2a8927a
XL
488 ExprKind::Range(_lhs, Some(rhs), _limits) => {
489 matches!(rhs.kind, ExprKind::Block(..))
490 }
f9f354fc
XL
491 _ => parser::contains_exterior_struct_lit(&inner),
492 })
b039eaaf 493 }
0bf4aa26 494
ba9703b0 495 fn emit_unused_delims_expr(
e1599b0c
XL
496 &self,
497 cx: &EarlyContext<'_>,
ba9703b0
XL
498 value: &ast::Expr,
499 ctx: UnusedDelimsCtx,
500 left_pos: Option<BytePos>,
501 right_pos: Option<BytePos>,
e1599b0c 502 ) {
c295e0f8
XL
503 let spans = match value.kind {
504 ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
505 let start = block.stmts[0].span;
506 let end = block.stmts[block.stmts.len() - 1].span;
f2b60f7d
FG
507 if let Some(start) = start.find_ancestor_inside(value.span)
508 && let Some(end) = end.find_ancestor_inside(value.span)
509 {
510 Some((
511 value.span.with_hi(start.lo()),
512 value.span.with_lo(end.hi()),
513 ))
c295e0f8 514 } else {
f2b60f7d 515 None
c295e0f8
XL
516 }
517 }
518 ast::ExprKind::Paren(ref expr) => {
f2b60f7d
FG
519 let expr_span = expr.span.find_ancestor_inside(value.span);
520 if let Some(expr_span) = expr_span {
521 Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
c295e0f8 522 } else {
f2b60f7d 523 None
c295e0f8
XL
524 }
525 }
526 _ => return,
ba9703b0
XL
527 };
528 let keep_space = (
5869c6ff
XL
529 left_pos.map_or(false, |s| s >= value.span.lo()),
530 right_pos.map_or(false, |s| s <= value.span.hi()),
ba9703b0 531 );
f2b60f7d 532 self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
0bf4aa26
XL
533 }
534
ba9703b0
XL
535 fn emit_unused_delims(
536 &self,
dfeec247 537 cx: &EarlyContext<'_>,
f2b60f7d
FG
538 value_span: Span,
539 spans: Option<(Span, Span)>,
dfeec247
XL
540 msg: &str,
541 keep_space: (bool, bool),
542 ) {
f2b60f7d
FG
543 let primary_span = if let Some((lo, hi)) = spans {
544 MultiSpan::from(vec![lo, hi])
545 } else {
546 MultiSpan::from(value_span)
547 };
548 cx.struct_span_lint(self.lint(), primary_span, |lint| {
549 let mut db = lint.build(fluent::lint::unused_delim);
550 db.set_arg("delim", Self::DELIM_STR);
551 db.set_arg("item", msg);
552 if let Some((lo, hi)) = spans {
553 let replacement = vec![
554 (lo, if keep_space.0 { " ".into() } else { "".into() }),
555 (hi, if keep_space.1 { " ".into() } else { "".into() }),
556 ];
557 db.multipart_suggestion(
064997fb
FG
558 fluent::lint::suggestion,
559 replacement,
560 Applicability::MachineApplicable,
f2b60f7d
FG
561 );
562 }
563 db.emit();
74b04a01 564 });
0bf4aa26 565 }
b039eaaf 566
9fa01778 567 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
3dfed10e 568 use rustc_ast::ExprKind::*;
ba9703b0
XL
569 let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
570 // Do not lint `unused_braces` in `if let` expressions.
6a06907d 571 If(ref cond, ref block, _)
94222f64
XL
572 if !matches!(cond.kind, Let(_, _, _))
573 || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
ba9703b0 574 {
dfeec247 575 let left = e.span.lo() + rustc_span::BytePos(2);
416331ca 576 let right = block.span.lo();
ba9703b0 577 (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
416331ca
XL
578 }
579
3dfed10e
XL
580 // Do not lint `unused_braces` in `while let` expressions.
581 While(ref cond, ref block, ..)
94222f64
XL
582 if !matches!(cond.kind, Let(_, _, _))
583 || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
3dfed10e 584 {
dfeec247 585 let left = e.span.lo() + rustc_span::BytePos(5);
416331ca 586 let right = block.span.lo();
ba9703b0 587 (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
dfeec247 588 }
416331ca 589
ba9703b0
XL
590 ForLoop(_, ref cond, ref block, ..) => {
591 (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
416331ca
XL
592 }
593
ba9703b0 594 Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
dfeec247 595 let left = e.span.lo() + rustc_span::BytePos(5);
ba9703b0 596 (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
416331ca
XL
597 }
598
599 Ret(Some(ref value)) => {
dfeec247 600 let left = e.span.lo() + rustc_span::BytePos(3);
ba9703b0 601 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
416331ca
XL
602 }
603
ba9703b0
XL
604 Assign(_, ref value, _) | AssignOp(.., ref value) => {
605 (value, UnusedDelimsCtx::AssignedValue, false, None, None)
606 }
2c00a5a8
XL
607 // either function/method call, or something this lint doesn't care about
608 ref call_or_other => {
ba9703b0
XL
609 let (args_to_check, ctx) = match *call_or_other {
610 Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
611 // first "argument" is self (which sometimes needs delims)
f035d41b 612 MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
2c00a5a8 613 // actual catch-all arm
0bf4aa26
XL
614 _ => {
615 return;
616 }
617 };
2c00a5a8
XL
618 // Don't lint if this is a nested macro expansion: otherwise, the lint could
619 // trigger in situations that macro authors shouldn't have to care about, e.g.,
620 // when a parenthesized token tree matched in one macro expansion is matched as
621 // an expression in another and used as a fn/method argument (Issue #47775)
e1599b0c
XL
622 if e.span.ctxt().outer_expn_data().call_site.from_expansion() {
623 return;
2c00a5a8 624 }
2c00a5a8 625 for arg in args_to_check {
ba9703b0 626 self.check_unused_delims_expr(cx, arg, ctx, false, None, None);
2c00a5a8
XL
627 }
628 return;
629 }
b039eaaf 630 };
ba9703b0
XL
631 self.check_unused_delims_expr(cx, &value, ctx, followed_by_block, left_pos, right_pos);
632 }
633
634 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
635 match s.kind {
636 StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
94222f64
XL
637 if let Some((init, els)) = local.kind.init_else_opt() {
638 let ctx = match els {
639 None => UnusedDelimsCtx::AssignedValue,
640 Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
641 };
642 self.check_unused_delims_expr(cx, init, ctx, false, None, None);
ba9703b0
XL
643 }
644 }
645 StmtKind::Expr(ref expr) => {
646 self.check_unused_delims_expr(
647 cx,
648 &expr,
649 UnusedDelimsCtx::BlockRetValue,
650 false,
651 None,
652 None,
653 );
654 }
655 _ => {}
656 }
657 }
658
659 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
660 use ast::ItemKind::*;
661
662 if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind {
663 self.check_unused_delims_expr(
664 cx,
665 expr,
666 UnusedDelimsCtx::AssignedValue,
667 false,
668 None,
669 None,
670 );
671 }
672 }
673}
674
675declare_lint! {
1b1a35ee
XL
676 /// The `unused_parens` lint detects `if`, `match`, `while` and `return`
677 /// with parentheses; they do not need them.
678 ///
679 /// ### Examples
680 ///
681 /// ```rust
682 /// if(true) {}
683 /// ```
684 ///
685 /// {{produces}}
686 ///
687 /// ### Explanation
688 ///
3c0e092e 689 /// The parentheses are not needed, and should be removed. This is the
1b1a35ee 690 /// preferred style for writing these expressions.
ba9703b0
XL
691 pub(super) UNUSED_PARENS,
692 Warn,
693 "`if`, `match`, `while` and `return` do not need parentheses"
694}
695
696declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
697
698impl UnusedDelimLint for UnusedParens {
699 const DELIM_STR: &'static str = "parentheses";
700
701 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
702
703 fn lint(&self) -> &'static Lint {
704 UNUSED_PARENS
705 }
706
707 fn check_unused_delims_expr(
708 &self,
709 cx: &EarlyContext<'_>,
710 value: &ast::Expr,
711 ctx: UnusedDelimsCtx,
712 followed_by_block: bool,
713 left_pos: Option<BytePos>,
714 right_pos: Option<BytePos>,
715 ) {
716 match value.kind {
717 ast::ExprKind::Paren(ref inner) => {
94222f64
XL
718 let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
719 if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else)
ba9703b0
XL
720 && value.attrs.is_empty()
721 && !value.span.from_expansion()
29967ef6
XL
722 && (ctx != UnusedDelimsCtx::LetScrutineeExpr
723 || !matches!(inner.kind, ast::ExprKind::Binary(
724 rustc_span::source_map::Spanned { node, .. },
725 _,
726 _,
727 ) if node.lazy()))
ba9703b0
XL
728 {
729 self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
730 }
731 }
94222f64 732 ast::ExprKind::Let(_, ref expr, _) => {
ba9703b0
XL
733 self.check_unused_delims_expr(
734 cx,
735 expr,
736 UnusedDelimsCtx::LetScrutineeExpr,
737 followed_by_block,
738 None,
739 None,
740 );
741 }
742 _ => {}
743 }
744 }
745}
746
747impl UnusedParens {
748 fn check_unused_parens_pat(
749 &self,
750 cx: &EarlyContext<'_>,
751 value: &ast::Pat,
752 avoid_or: bool,
753 avoid_mut: bool,
754 ) {
f2b60f7d 755 use ast::{BindingAnnotation, PatKind};
ba9703b0
XL
756
757 if let PatKind::Paren(inner) = &value.kind {
758 match inner.kind {
759 // The lint visitor will visit each subpattern of `p`. We do not want to lint
760 // any range pattern no matter where it occurs in the pattern. For something like
761 // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
762 // that if there are unnecessary parens they serve a purpose of readability.
763 PatKind::Range(..) => return,
764 // Avoid `p0 | .. | pn` if we should.
765 PatKind::Or(..) if avoid_or => return,
766 // Avoid `mut x` and `mut x @ p` if we should:
f2b60f7d
FG
767 PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => {
768 return;
769 }
ba9703b0
XL
770 // Otherwise proceed with linting.
771 _ => {}
772 }
f2b60f7d
FG
773 let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
774 Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
c295e0f8 775 } else {
f2b60f7d 776 None
c295e0f8 777 };
f2b60f7d 778 self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
ba9703b0
XL
779 }
780 }
781}
782
783impl EarlyLintPass for UnusedParens {
784 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
6a06907d 785 match e.kind {
94222f64 786 ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
6a06907d
XL
787 self.check_unused_parens_pat(cx, pat, false, false);
788 }
789 // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
790 // handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
791 // want to complain about things like `if let 42 = (42)`.
792 ExprKind::If(ref cond, ref block, ref else_)
793 if matches!(cond.peel_parens().kind, ExprKind::Let(..)) =>
794 {
795 self.check_unused_delims_expr(
796 cx,
797 cond.peel_parens(),
798 UnusedDelimsCtx::LetScrutineeExpr,
799 true,
800 None,
801 None,
802 );
803 for stmt in &block.stmts {
804 <Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
805 }
806 if let Some(e) = else_ {
807 <Self as UnusedDelimLint>::check_expr(self, cx, e);
808 }
809 return;
810 }
064997fb
FG
811 ExprKind::Match(ref _expr, ref arm) => {
812 for a in arm {
813 self.check_unused_delims_expr(
814 cx,
815 &a.body,
816 UnusedDelimsCtx::MatchArmExpr,
817 false,
818 None,
819 None,
820 );
821 }
822 }
6a06907d 823 _ => {}
ba9703b0
XL
824 }
825
826 <Self as UnusedDelimLint>::check_expr(self, cx, e)
0bf4aa26
XL
827 }
828
48663c56 829 fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
dfeec247 830 use ast::{Mutability, PatKind::*};
e74abb32 831 match &p.kind {
e1599b0c
XL
832 // Do not lint on `(..)` as that will result in the other arms being useless.
833 Paren(_)
834 // The other cases do not contain sub-patterns.
ba9703b0 835 | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
e1599b0c 836 // These are list-like patterns; parens can always be removed.
17df50a5 837 TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
e1599b0c
XL
838 self.check_unused_parens_pat(cx, p, false, false);
839 },
17df50a5 840 Struct(_, _, fps, _) => for f in fps {
e1599b0c
XL
841 self.check_unused_parens_pat(cx, &f.pat, false, false);
842 },
843 // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
844 Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
845 // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
846 // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
dfeec247 847 Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
0bf4aa26 848 }
b039eaaf
SL
849 }
850
ba9703b0
XL
851 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
852 if let StmtKind::Local(ref local) = s.kind {
6a06907d 853 self.check_unused_parens_pat(cx, &local.pat, true, false);
0bf4aa26 854 }
ba9703b0
XL
855
856 <Self as UnusedDelimLint>::check_stmt(self, cx, s)
b039eaaf 857 }
e1599b0c
XL
858
859 fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
860 self.check_unused_parens_pat(cx, &param.pat, true, false);
861 }
862
863 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
864 self.check_unused_parens_pat(cx, &arm.pat, false, false);
865 }
e74abb32
XL
866
867 fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
5869c6ff 868 if let ast::TyKind::Paren(r) = &ty.kind {
e74abb32 869 match &r.kind {
5869c6ff
XL
870 ast::TyKind::TraitObject(..) => {}
871 ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
872 ast::TyKind::Array(_, len) => {
ba9703b0
XL
873 self.check_unused_delims_expr(
874 cx,
875 &len.value,
876 UnusedDelimsCtx::ArrayLenExpr,
877 false,
878 None,
879 None,
880 );
881 }
e74abb32 882 _ => {
f2b60f7d
FG
883 let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
884 Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
c295e0f8 885 } else {
f2b60f7d 886 None
c295e0f8 887 };
f2b60f7d 888 self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
e74abb32
XL
889 }
890 }
891 }
892 }
74b04a01
XL
893
894 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
ba9703b0
XL
895 <Self as UnusedDelimLint>::check_item(self, cx, item)
896 }
897}
74b04a01 898
ba9703b0 899declare_lint! {
1b1a35ee
XL
900 /// The `unused_braces` lint detects unnecessary braces around an
901 /// expression.
902 ///
903 /// ### Example
904 ///
905 /// ```rust
906 /// if { true } {
907 /// // ...
908 /// }
909 /// ```
910 ///
911 /// {{produces}}
912 ///
913 /// ### Explanation
914 ///
915 /// The braces are not needed, and should be removed. This is the
916 /// preferred style for writing these expressions.
ba9703b0
XL
917 pub(super) UNUSED_BRACES,
918 Warn,
919 "unnecessary braces around an expression"
920}
921
922declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
923
924impl UnusedDelimLint for UnusedBraces {
925 const DELIM_STR: &'static str = "braces";
926
927 const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
928
929 fn lint(&self) -> &'static Lint {
930 UNUSED_BRACES
931 }
932
933 fn check_unused_delims_expr(
934 &self,
935 cx: &EarlyContext<'_>,
936 value: &ast::Expr,
937 ctx: UnusedDelimsCtx,
938 followed_by_block: bool,
939 left_pos: Option<BytePos>,
940 right_pos: Option<BytePos>,
941 ) {
942 match value.kind {
943 ast::ExprKind::Block(ref inner, None)
944 if inner.rules == ast::BlockCheckMode::Default =>
945 {
946 // emit a warning under the following conditions:
947 //
948 // - the block does not have a label
949 // - the block is not `unsafe`
950 // - the block contains exactly one expression (do not lint `{ expr; }`)
951 // - `followed_by_block` is true and the internal expr may contain a `{`
952 // - the block is not multiline (do not lint multiline match arms)
953 // ```
954 // match expr {
955 // Pattern => {
956 // somewhat_long_expression
957 // }
958 // // ...
959 // }
960 // ```
961 // - the block has no attribute and was not created inside a macro
962 // - if the block is an `anon_const`, the inner expr must be a literal
963 // (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
964 //
965 // FIXME(const_generics): handle paths when #67075 is fixed.
966 if let [stmt] = inner.stmts.as_slice() {
967 if let ast::StmtKind::Expr(ref expr) = stmt.kind {
94222f64 968 if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
ba9703b0
XL
969 && (ctx != UnusedDelimsCtx::AnonConst
970 || matches!(expr.kind, ast::ExprKind::Lit(_)))
ba9703b0
XL
971 && !cx.sess().source_map().is_multiline(value.span)
972 && value.attrs.is_empty()
973 && !value.span.from_expansion()
974 {
975 self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
976 }
977 }
978 }
979 }
94222f64 980 ast::ExprKind::Let(_, ref expr, _) => {
ba9703b0
XL
981 self.check_unused_delims_expr(
982 cx,
983 expr,
984 UnusedDelimsCtx::LetScrutineeExpr,
985 followed_by_block,
986 None,
987 None,
988 );
989 }
990 _ => {}
74b04a01
XL
991 }
992 }
b039eaaf
SL
993}
994
ba9703b0 995impl EarlyLintPass for UnusedBraces {
29967ef6
XL
996 fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
997 <Self as UnusedDelimLint>::check_stmt(self, cx, s)
998 }
999
ba9703b0 1000 fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
29967ef6
XL
1001 <Self as UnusedDelimLint>::check_expr(self, cx, e);
1002
1003 if let ExprKind::Repeat(_, ref anon_const) = e.kind {
1004 self.check_unused_delims_expr(
1005 cx,
1006 &anon_const.value,
1007 UnusedDelimsCtx::AnonConst,
1008 false,
1009 None,
1010 None,
1011 );
1012 }
ba9703b0
XL
1013 }
1014
29967ef6
XL
1015 fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
1016 if let ast::GenericArg::Const(ct) = arg {
1017 self.check_unused_delims_expr(
1018 cx,
1019 &ct.value,
1020 UnusedDelimsCtx::AnonConst,
1021 false,
1022 None,
1023 None,
1024 );
1025 }
ba9703b0
XL
1026 }
1027
29967ef6
XL
1028 fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
1029 if let Some(anon_const) = &v.disr_expr {
1030 self.check_unused_delims_expr(
1031 cx,
1032 &anon_const.value,
1033 UnusedDelimsCtx::AnonConst,
1034 false,
1035 None,
1036 None,
1037 );
1038 }
ba9703b0
XL
1039 }
1040
1041 fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
29967ef6
XL
1042 match ty.kind {
1043 ast::TyKind::Array(_, ref len) => {
ba9703b0
XL
1044 self.check_unused_delims_expr(
1045 cx,
1046 &len.value,
1047 UnusedDelimsCtx::ArrayLenExpr,
1048 false,
1049 None,
1050 None,
1051 );
1052 }
29967ef6
XL
1053
1054 ast::TyKind::Typeof(ref anon_const) => {
1055 self.check_unused_delims_expr(
1056 cx,
1057 &anon_const.value,
1058 UnusedDelimsCtx::AnonConst,
1059 false,
1060 None,
1061 None,
1062 );
1063 }
1064
1065 _ => {}
ba9703b0
XL
1066 }
1067 }
1068
1069 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1070 <Self as UnusedDelimLint>::check_item(self, cx, item)
1071 }
1072}
1073
b039eaaf 1074declare_lint! {
1b1a35ee
XL
1075 /// The `unused_import_braces` lint catches unnecessary braces around an
1076 /// imported item.
1077 ///
1078 /// ### Example
1079 ///
1080 /// ```rust,compile_fail
1081 /// #![deny(unused_import_braces)]
1082 /// use test::{A};
1083 ///
1084 /// pub mod test {
1085 /// pub struct A;
1086 /// }
1087 /// # fn main() {}
1088 /// ```
1089 ///
1090 /// {{produces}}
1091 ///
1092 /// ### Explanation
1093 ///
1094 /// If there is only a single item, then remove the braces (`use test::A;`
1095 /// for example).
1096 ///
1097 /// This lint is "allow" by default because it is only enforcing a
1098 /// stylistic choice.
b039eaaf
SL
1099 UNUSED_IMPORT_BRACES,
1100 Allow,
1101 "unnecessary braces around an imported item"
1102}
1103
532ac7d7 1104declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
b039eaaf 1105
ff7c6d11 1106impl UnusedImportBraces {
9fa01778 1107 fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
ff7c6d11
XL
1108 if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
1109 // Recursively check nested UseTrees
1110 for &(ref tree, _) in items {
1111 self.check_use_tree(cx, tree, item);
1112 }
1113
1114 // Trigger the lint only if there is one nested item
1115 if items.len() != 1 {
1116 return;
1117 }
1118
1119 // Trigger the lint if the nested item is a non-self single item
e1599b0c 1120 let node_name = match items[0].0.kind {
94b46f34 1121 ast::UseTreeKind::Simple(rename, ..) => {
83c7162d 1122 let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
dc9dc135 1123 if orig_ident.name == kw::SelfLower {
ff7c6d11 1124 return;
ff7c6d11 1125 }
e1599b0c 1126 rename.unwrap_or(orig_ident).name
ff7c6d11 1127 }
e1599b0c
XL
1128 ast::UseTreeKind::Glob => Symbol::intern("*"),
1129 ast::UseTreeKind::Nested(_) => return,
1130 };
ff7c6d11 1131
74b04a01 1132 cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
064997fb 1133 lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit();
74b04a01 1134 });
ff7c6d11
XL
1135 }
1136 }
1137}
1138
476ff2be 1139impl EarlyLintPass for UnusedImportBraces {
9fa01778 1140 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
e74abb32 1141 if let ast::ItemKind::Use(ref use_tree) = item.kind {
ff7c6d11 1142 self.check_use_tree(cx, use_tree, item);
b039eaaf
SL
1143 }
1144 }
1145}
1146
1147declare_lint! {
1b1a35ee
XL
1148 /// The `unused_allocation` lint detects unnecessary allocations that can
1149 /// be eliminated.
1150 ///
1151 /// ### Example
1152 ///
1153 /// ```rust
1154 /// #![feature(box_syntax)]
1155 /// fn main() {
fc512014 1156 /// let a = (box [1, 2, 3]).len();
1b1a35ee
XL
1157 /// }
1158 /// ```
1159 ///
1160 /// {{produces}}
1161 ///
1162 /// ### Explanation
1163 ///
1164 /// When a `box` expression is immediately coerced to a reference, then
1165 /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
1166 /// should be used instead to avoid the allocation.
abe05a73 1167 pub(super) UNUSED_ALLOCATION,
b039eaaf
SL
1168 Warn,
1169 "detects unnecessary allocations that can be eliminated"
1170}
1171
532ac7d7 1172declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
b039eaaf 1173
f035d41b
XL
1174impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
1175 fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
e74abb32 1176 match e.kind {
8faf50e0 1177 hir::ExprKind::Box(_) => {}
c30ab7b3 1178 _ => return,
b039eaaf
SL
1179 }
1180
3dfed10e 1181 for adj in cx.typeck_results().expr_adjustments(e) {
7cac9316 1182 if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
74b04a01 1183 cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
064997fb
FG
1184 lint.build(match m {
1185 adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
74b04a01 1186 adjustment::AutoBorrowMutability::Mut { .. } => {
064997fb 1187 fluent::lint::unused_allocation_mut
74b04a01 1188 }
064997fb
FG
1189 })
1190 .emit();
74b04a01 1191 });
b039eaaf
SL
1192 }
1193 }
1194 }
1195}