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