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