Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15659 - HKalbasi:unused-var, r=HKalbasi
Add `unused_variables` native diagnostic
bors 2023-09-25
parent 862a300 · parent ab52ba2 · commit 972a19f
-rw-r--r--crates/hir-ty/src/layout/tests/closure.rs4
-rw-r--r--crates/hir-ty/src/mir.rs8
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs88
-rw-r--r--crates/hir-ty/src/mir/eval.rs1
-rw-r--r--crates/hir-ty/src/mir/lower.rs19
-rw-r--r--crates/hir-ty/src/mir/monomorphization.rs1
-rw-r--r--crates/hir-ty/src/mir/pretty.rs5
-rw-r--r--crates/hir/src/diagnostics.rs6
-rw-r--r--crates/hir/src/lib.rs15
-rw-r--r--crates/ide-diagnostics/src/handlers/field_shorthand.rs6
-rw-r--r--crates/ide-diagnostics/src/handlers/incorrect_case.rs18
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs22
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_fields.rs3
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_match_arms.rs6
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_unsafe.rs48
-rw-r--r--crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs8
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs66
-rw-r--r--crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs20
-rw-r--r--crates/ide-diagnostics/src/handlers/type_mismatch.rs36
-rw-r--r--crates/ide-diagnostics/src/handlers/typed_hole.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/unused_variables.rs110
-rw-r--r--crates/ide-diagnostics/src/lib.rs2
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs12
-rw-r--r--crates/test-utils/src/minicore.rs38
24 files changed, 404 insertions, 142 deletions
diff --git a/crates/hir-ty/src/layout/tests/closure.rs b/crates/hir-ty/src/layout/tests/closure.rs
index bbe855a14d..939025461f 100644
--- a/crates/hir-ty/src/layout/tests/closure.rs
+++ b/crates/hir-ty/src/layout/tests/closure.rs
@@ -186,9 +186,9 @@ fn capture_specific_fields() {
fn match_pattern() {
size_and_align_expr! {
struct X(i64, i32, (u8, i128));
- let y: X = X(2, 5, (7, 3));
+ let _y: X = X(2, 5, (7, 3));
move |x: i64| {
- match y {
+ match _y {
_ => x,
}
}
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index e953058ccc..797f4c1248 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -280,7 +280,7 @@ impl ProjectionId {
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Place {
pub local: LocalId,
pub projection: ProjectionId,
@@ -1007,7 +1007,7 @@ pub enum Rvalue {
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatementKind {
Assign(Place, Rvalue),
- //FakeRead(Box<(FakeReadCause, Place)>),
+ FakeRead(Place),
//SetDiscriminant {
// place: Box<Place>,
// variant_index: VariantIdx,
@@ -1109,7 +1109,9 @@ impl MirBody {
}
}
}
- StatementKind::Deinit(p) => f(p, &mut self.projection_store),
+ StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
+ f(p, &mut self.projection_store)
+ }
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 41fb129652..74c5efd6c3 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -24,6 +24,7 @@ use super::{
pub enum MutabilityReason {
Mut { spans: Vec<MirSpan> },
Not,
+ Unused,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -144,7 +145,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
}
}
},
- StatementKind::Deinit(_)
+ StatementKind::FakeRead(_)
+ | StatementKind::Deinit(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@@ -264,7 +266,10 @@ fn ever_initialized_map(
is_ever_initialized = false;
}
}
- StatementKind::Deinit(_) | StatementKind::Nop | StatementKind::StorageLive(_) => (),
+ StatementKind::Deinit(_)
+ | StatementKind::FakeRead(_)
+ | StatementKind::Nop
+ | StatementKind::StorageLive(_) => (),
}
}
let Some(terminator) = &block.terminator else {
@@ -331,16 +336,37 @@ fn ever_initialized_map(
result
}
+fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ match &mut result[local] {
+ MutabilityReason::Mut { spans } => spans.push(span),
+ it @ (MutabilityReason::Not | MutabilityReason::Unused) => {
+ *it = MutabilityReason::Mut { spans: vec![span] }
+ }
+ };
+}
+
+fn record_usage(local: LocalId, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ match &mut result[local] {
+ it @ MutabilityReason::Unused => {
+ *it = MutabilityReason::Not;
+ }
+ _ => (),
+ };
+}
+
+fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ if let Operand::Copy(p) | Operand::Move(p) = arg {
+ record_usage(p.local, result);
+ }
+}
+
fn mutability_of_locals(
db: &dyn HirDatabase,
body: &MirBody,
) -> ArenaMap<LocalId, MutabilityReason> {
let mut result: ArenaMap<LocalId, MutabilityReason> =
- body.locals.iter().map(|it| (it.0, MutabilityReason::Not)).collect();
- let mut push_mut_span = |local, span| match &mut result[local] {
- MutabilityReason::Mut { spans } => spans.push(span),
- it @ MutabilityReason::Not => *it = MutabilityReason::Mut { spans: vec![span] },
- };
+ body.locals.iter().map(|it| (it.0, MutabilityReason::Unused)).collect();
+
let ever_init_maps = ever_initialized_map(db, body);
for (block_id, mut ever_init_map) in ever_init_maps.into_iter() {
let block = &body.basic_blocks[block_id];
@@ -350,23 +376,51 @@ fn mutability_of_locals(
match place_case(db, body, place) {
ProjectionCase::Direct => {
if ever_init_map.get(place.local).copied().unwrap_or_default() {
- push_mut_span(place.local, statement.span);
+ push_mut_span(place.local, statement.span, &mut result);
} else {
ever_init_map.insert(place.local, true);
}
}
ProjectionCase::DirectPart => {
// Partial initialization is not supported, so it is definitely `mut`
- push_mut_span(place.local, statement.span);
+ push_mut_span(place.local, statement.span, &mut result);
+ }
+ ProjectionCase::Indirect => {
+ record_usage(place.local, &mut result);
}
- ProjectionCase::Indirect => (),
+ }
+ match value {
+ Rvalue::CopyForDeref(p)
+ | Rvalue::Discriminant(p)
+ | Rvalue::Len(p)
+ | Rvalue::Ref(_, p) => {
+ record_usage(p.local, &mut result);
+ }
+ Rvalue::Use(o)
+ | Rvalue::Repeat(o, _)
+ | Rvalue::Cast(_, o, _)
+ | Rvalue::UnaryOp(_, o) => record_usage_for_operand(o, &mut result),
+ Rvalue::CheckedBinaryOp(_, o1, o2) => {
+ for o in [o1, o2] {
+ record_usage_for_operand(o, &mut result);
+ }
+ }
+ Rvalue::Aggregate(_, args) => {
+ for arg in args.iter() {
+ record_usage_for_operand(arg, &mut result);
+ }
+ }
+ Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
}
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
if place_case(db, body, p) != ProjectionCase::Indirect {
- push_mut_span(p.local, statement.span);
+ push_mut_span(p.local, statement.span, &mut result);
}
}
}
+ StatementKind::FakeRead(p) => {
+ record_usage(p.local, &mut result);
+ }
StatementKind::StorageDead(p) => {
ever_init_map.insert(*p, false);
}
@@ -386,15 +440,21 @@ fn mutability_of_locals(
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
- | TerminatorKind::SwitchInt { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::Yield { .. } => (),
- TerminatorKind::Call { destination, .. } => {
+ TerminatorKind::SwitchInt { discr, targets: _ } => {
+ record_usage_for_operand(discr, &mut result);
+ }
+ TerminatorKind::Call { destination, args, func, .. } => {
+ record_usage_for_operand(func, &mut result);
+ for arg in args.iter() {
+ record_usage_for_operand(arg, &mut result);
+ }
if destination.projection.lookup(&body.projection_store).len() == 0 {
if ever_init_map.get(destination.local).copied().unwrap_or_default() {
- push_mut_span(destination.local, MirSpan::Unknown);
+ push_mut_span(destination.local, MirSpan::Unknown, &mut result);
} else {
ever_init_map.insert(destination.local, true);
}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 4364e0d323..98c78f7f30 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -842,6 +842,7 @@ impl Evaluator<'_> {
}
StatementKind::Deinit(_) => not_supported!("de-init statement"),
StatementKind::StorageLive(_)
+ | StatementKind::FakeRead(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
}
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index dd2dba717f..9905d52214 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -529,6 +529,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
+ self.push_fake_read(current, cond_place, expr_id.into());
let (then_target, else_target) =
self.pattern_match(current, None, cond_place, *pat)?;
self.write_bytes_to_place(
@@ -668,6 +669,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
+ self.push_fake_read(current, cond_place, expr_id.into());
let mut end = None;
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) =
@@ -1299,6 +1301,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
+ self.push_fake_read_for_operand(current, rhs_op, span);
return Ok(Some(current));
}
if matches!(
@@ -1575,6 +1578,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.result.basic_blocks[block].statements.push(statement);
}
+ fn push_fake_read(&mut self, block: BasicBlockId, p: Place, span: MirSpan) {
+ self.push_statement(block, StatementKind::FakeRead(p).with_span(span));
+ }
+
+ fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) {
+ if let Operand::Move(p) | Operand::Copy(p) = operand {
+ self.push_fake_read(block, p, span);
+ }
+ }
+
fn push_assignment(
&mut self,
block: BasicBlockId,
@@ -1733,6 +1746,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
current = c;
+ self.push_fake_read(current, init_place, span);
(current, else_block) =
self.pattern_match(current, None, init_place, *pat)?;
match (else_block, else_branch) {
@@ -1760,13 +1774,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
}
- hir_def::hir::Statement::Expr { expr, has_semi: _ } => {
+ &hir_def::hir::Statement::Expr { expr, has_semi: _ } => {
let scope2 = self.push_drop_scope();
- let Some((_, c)) = self.lower_expr_as_place(current, *expr, true)? else {
+ let Some((p, c)) = self.lower_expr_as_place(current, expr, true)? else {
scope2.pop_assume_dropped(self);
scope.pop_assume_dropped(self);
return Ok(None);
};
+ self.push_fake_read(c, p, expr.into());
current = scope2.pop_and_drop(self, c);
}
}
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index df16d0d820..7d2bb95d93 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -248,6 +248,7 @@ impl Filler<'_> {
| Rvalue::CopyForDeref(_) => (),
},
StatementKind::Deinit(_)
+ | StatementKind::FakeRead(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index 0108859ff3..6e42bee97f 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -233,6 +233,11 @@ impl<'a> MirPrettyCtx<'a> {
this.place(p);
wln!(this, ");");
}
+ StatementKind::FakeRead(p) => {
+ w!(this, "FakeRead(");
+ this.place(p);
+ wln!(this, ");");
+ }
StatementKind::Nop => wln!(this, "Nop;"),
}
}
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 479138b67f..66ad95c559 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -66,6 +66,7 @@ diagnostics![
UnresolvedModule,
UnresolvedProcMacro,
UnusedMut,
+ UnusedVariable,
];
#[derive(Debug)]
@@ -271,6 +272,11 @@ pub struct UnusedMut {
}
#[derive(Debug)]
+pub struct UnusedVariable {
+ pub local: Local,
+}
+
+#[derive(Debug)]
pub struct MovedOutOfRef {
pub ty: Type,
pub span: InFile<SyntaxNodePtr>,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b215ed38f2..a6c6c0dbb8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -98,7 +98,7 @@ pub use crate::{
ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel,
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
- UnresolvedProcMacro, UnusedMut,
+ UnresolvedProcMacro, UnusedMut, UnusedVariable,
},
has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -1697,9 +1697,20 @@ impl DefWithBody {
// Skip synthetic bindings
continue;
}
- let need_mut = &mol[local];
+ let mut need_mut = &mol[local];
+ if body[binding_id].name.as_str() == Some("self")
+ && need_mut == &mir::MutabilityReason::Unused
+ {
+ need_mut = &mir::MutabilityReason::Not;
+ }
let local = Local { parent: self.into(), binding_id };
match (need_mut, local.is_mut(db)) {
+ (mir::MutabilityReason::Unused, _) => {
+ let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with("_"));
+ if !should_ignore {
+ acc.push(UnusedVariable { local }.into())
+ }
+ }
(mir::MutabilityReason::Mut { .. }, true)
| (mir::MutabilityReason::Not, false) => (),
(mir::MutabilityReason::Mut { spans }, false) => {
diff --git a/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/crates/ide-diagnostics/src/handlers/field_shorthand.rs
index 3b69640af9..9ed8199ae4 100644
--- a/crates/ide-diagnostics/src/handlers/field_shorthand.rs
+++ b/crates/ide-diagnostics/src/handlers/field_shorthand.rs
@@ -166,7 +166,7 @@ fn main() {
check_diagnostics(
r#"
struct A { a: &'static str }
-fn f(a: A) { let A { a: hello } = a; }
+fn f(a: A) { let A { a: _hello } = a; }
"#,
);
check_diagnostics(
@@ -181,12 +181,14 @@ fn f(a: A) { let A { 0: 0 } = a; }
struct A { a: &'static str }
fn f(a: A) {
let A { a$0: a } = a;
+ _ = a;
}
"#,
r#"
struct A { a: &'static str }
fn f(a: A) {
let A { a } = a;
+ _ = a;
}
"#,
);
@@ -196,12 +198,14 @@ fn f(a: A) {
struct A { a: &'static str, b: &'static str }
fn f(a: A) {
let A { a$0: a, b } = a;
+ _ = (a, b);
}
"#,
r#"
struct A { a: &'static str, b: &'static str }
fn f(a: A) {
let A { a, b } = a;
+ _ = (a, b);
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 235062bf53..7824011db6 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -175,10 +175,10 @@ fn NonSnakeCaseName() {}
fn incorrect_function_params() {
check_diagnostics(
r#"
-fn foo(SomeParam: u8) {}
+fn foo(SomeParam: u8) { _ = SomeParam; }
// ^^^^^^^^^ 💡 warn: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
-fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
+fn foo2(ok_param: &str, CAPS_PARAM: u8) { _ = (ok_param, CAPS_PARAM); }
// ^^^^^^^^^^ 💡 warn: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
"#,
);
@@ -188,6 +188,7 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
fn incorrect_variable_names() {
check_diagnostics(
r#"
+#[allow(unused)]
fn foo() {
let SOME_VALUE = 10;
// ^^^^^^^^^^ 💡 warn: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
@@ -294,6 +295,7 @@ impl someStruct {
// ^^^^^^^^ 💡 warn: Function `SomeFunc` should have snake_case name, e.g. `some_func`
let WHY_VAR_IS_CAPS = 10;
// ^^^^^^^^^^^^^^^ 💡 warn: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
+ _ = WHY_VAR_IS_CAPS;
}
}
"#,
@@ -306,6 +308,7 @@ impl someStruct {
r#"
enum Option { Some, None }
+#[allow(unused)]
fn main() {
match Option::None {
None => (),
@@ -322,6 +325,7 @@ fn main() {
r#"
enum Option { Some, None }
+#[allow(unused)]
fn main() {
match Option::None {
SOME_VAR @ None => (),
@@ -349,7 +353,9 @@ enum E {
}
mod F {
- fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
+ fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {
+ _ = BAD_NAME_HI;
+ }
}
"#,
);
@@ -395,7 +401,7 @@ fn qualify() {
#[test] // Issue #8809.
fn parenthesized_parameter() {
- check_diagnostics(r#"fn f((O): _) {}"#)
+ check_diagnostics(r#"fn f((O): _) { _ = O; }"#)
}
#[test]
@@ -472,7 +478,9 @@ mod CheckBadStyle {
mod F {
#![allow(non_snake_case)]
- fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
+ fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {
+ _ = BAD_NAME_HI;
+ }
}
#[allow(non_snake_case, non_camel_case_types)]
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 8265e0b1c1..ede9858c72 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -131,7 +131,7 @@ fn f() { zero(); }
fn simple_free_fn_one() {
check_diagnostics(
r#"
-fn one(arg: u8) {}
+fn one(_arg: u8) {}
fn f() { one(); }
//^^ error: expected 1 argument, found 0
"#,
@@ -139,7 +139,7 @@ fn f() { one(); }
check_diagnostics(
r#"
-fn one(arg: u8) {}
+fn one(_arg: u8) {}
fn f() { one(1); }
"#,
);
@@ -176,7 +176,7 @@ fn f() {
check_diagnostics(
r#"
struct S;
-impl S { fn method(&self, arg: u8) {} }
+impl S { fn method(&self, _arg: u8) {} }
fn f() {
S.method();
@@ -187,7 +187,7 @@ impl S { fn method(&self, arg: u8) {} }
check_diagnostics(
r#"
struct S;
-impl S { fn method(&self, arg: u8) {} }
+impl S { fn method(&self, _arg: u8) {} }
fn f() {
S::method(&S, 0);
@@ -335,8 +335,8 @@ struct S;
impl S {
fn method(#[cfg(NEVER)] self) {}
- fn method2(#[cfg(NEVER)] self, arg: u8) {}
- fn method3(self, #[cfg(NEVER)] arg: u8) {}
+ fn method2(#[cfg(NEVER)] self, _arg: u8) {}
+ fn method3(self, #[cfg(NEVER)] _arg: u8) {}
}
extern "C" {
@@ -365,8 +365,8 @@ fn main() {
r#"
#[rustc_legacy_const_generics(1, 3)]
fn mixed<const N1: &'static str, const N2: bool>(
- a: u8,
- b: i8,
+ _a: u8,
+ _b: i8,
) {}
fn f() {
@@ -376,8 +376,8 @@ fn f() {
#[rustc_legacy_const_generics(1, 3)]
fn b<const N1: u8, const N2: u8>(
- a: u8,
- b: u8,
+ _a: u8,
+ _b: u8,
) {}
fn g() {
@@ -403,7 +403,7 @@ fn f(
// ^^ error: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
S(e, f, .., g, d): S
// ^^^^^^^^^ error: this pattern has 4 fields, but the corresponding tuple struct has 2 fields
-) {}
+) { _ = (a, b, c, d, e, f, g); }
"#,
)
}
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index acc31cd117..3178c7fa2b 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -290,6 +290,7 @@ fn x(a: S) {
struct S { s: u32 }
fn x(a: S) {
let S { ref s } = a;
+ _ = s;
}
",
)
@@ -626,7 +627,7 @@ struct TestStruct { one: i32, two: i64 }
fn test_fn() {
let one = 1;
- let s = TestStruct{ one, two: 2 };
+ let _s = TestStruct{ one, two: 2 };
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 06b03d3d19..84267d3d90 100644
--- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -19,6 +19,7 @@ pub(crate) fn missing_match_arms(
mod tests {
use crate::tests::check_diagnostics;
+ #[track_caller]
fn check_diagnostics_no_bails(ra_fixture: &str) {
cov_mark::check_count!(validate_match_bailed_out, 0);
crate::tests::check_diagnostics(ra_fixture)
@@ -564,6 +565,7 @@ fn bang(never: !) {
r#"
enum Option<T> { Some(T), None }
+#[allow(unused)]
fn main() {
// `Never` is deliberately not defined so that it's an uninferred type.
match Option::<Never>::None {
@@ -719,7 +721,7 @@ fn main() {
r#"
struct S { a: char}
fn main(v: S) {
- match v { S{ a } => {} }
+ match v { S{ a } => { _ = a; } }
match v { S{ a: _x } => {} }
match v { S{ a: 'a' } => {} }
match v { S{..} => {} }
@@ -901,7 +903,7 @@ enum E{ A, B }
fn foo() {
match &E::A {
E::A => {}
- x => {}
+ _x => {}
}
}",
);
diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 70b26009ba..0f695b2745 100644
--- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -100,9 +100,9 @@ mod tests {
r#"
fn main() {
let x = &5 as *const usize;
- unsafe { let y = *x; }
- let z = *x;
-} //^^💡 error: this operation is unsafe and requires an unsafe function or block
+ unsafe { let _y = *x; }
+ let _z = *x;
+} //^^💡 error: this operation is unsafe and requires an unsafe function or block
"#,
)
}
@@ -116,13 +116,13 @@ struct HasUnsafe;
impl HasUnsafe {
unsafe fn unsafe_fn(&self) {
let x = &5 as *const usize;
- let y = *x;
+ let _y = *x;
}
}
unsafe fn unsafe_fn() {
let x = &5 as *const usize;
- let y = *x;
+ let _y = *x;
}
fn main() {
@@ -152,10 +152,10 @@ struct Ty {
static mut STATIC_MUT: Ty = Ty { a: 0 };
fn main() {
- let x = STATIC_MUT.a;
- //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
+ let _x = STATIC_MUT.a;
+ //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
unsafe {
- let x = STATIC_MUT.a;
+ let _x = STATIC_MUT.a;
}
}
"#,
@@ -187,13 +187,13 @@ fn main() {
r#"
fn main() {
let x = &5 as *const usize;
- let z = *x$0;
+ let _z = *x$0;
}
"#,
r#"
fn main() {
let x = &5 as *const usize;
- let z = unsafe { *x };
+ let _z = unsafe { *x };
}
"#,
);
@@ -231,7 +231,7 @@ struct S(usize);
impl S {
unsafe fn func(&self) {
let x = &self.0 as *const usize;
- let z = *x;
+ let _z = *x;
}
}
fn main() {
@@ -244,7 +244,7 @@ struct S(usize);
impl S {
unsafe fn func(&self) {
let x = &self.0 as *const usize;
- let z = *x;
+ let _z = *x;
}
}
fn main() {
@@ -267,7 +267,7 @@ struct Ty {
static mut STATIC_MUT: Ty = Ty { a: 0 };
fn main() {
- let x = STATIC_MUT$0.a;
+ let _x = STATIC_MUT$0.a;
}
"#,
r#"
@@ -278,7 +278,7 @@ struct Ty {
static mut STATIC_MUT: Ty = Ty { a: 0 };
fn main() {
- let x = unsafe { STATIC_MUT.a };
+ let _x = unsafe { STATIC_MUT.a };
}
"#,
)
@@ -382,16 +382,16 @@ fn main() {
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x;
- x = STATIC_MUT$0;
+ let _x;
+ _x = STATIC_MUT$0;
}
"#,
r#"
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x;
- x = unsafe { STATIC_MUT };
+ let _x;
+ _x = unsafe { STATIC_MUT };
}
"#,
)
@@ -405,14 +405,14 @@ fn main() {
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = STATIC_MUT$0 + 1;
+ let _x = STATIC_MUT$0 + 1;
}
"#,
r#"
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = unsafe { STATIC_MUT } + 1;
+ let _x = unsafe { STATIC_MUT } + 1;
}
"#,
)
@@ -425,14 +425,14 @@ fn main() {
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = &STATIC_MUT$0;
+ let _x = &STATIC_MUT$0;
}
"#,
r#"
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = unsafe { &STATIC_MUT };
+ let _x = unsafe { &STATIC_MUT };
}
"#,
)
@@ -445,14 +445,14 @@ fn main() {
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = &&STATIC_MUT$0;
+ let _x = &&STATIC_MUT$0;
}
"#,
r#"
static mut STATIC_MUT: u8 = 0;
fn main() {
- let x = unsafe { &&STATIC_MUT };
+ let _x = unsafe { &&STATIC_MUT };
}
"#,
)
diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 3aa4aa9702..20175b3fd5 100644
--- a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -29,6 +29,7 @@ fn main() {
let a = &X;
let b = *a;
//^ error: cannot move `X` out of reference
+ _ = b;
}
"#,
);
@@ -46,6 +47,7 @@ fn main() {
let b = a.0;
//^ error: cannot move `X` out of reference
let y = a.1;
+ _ = (b, y);
}
"#,
);
@@ -59,8 +61,8 @@ fn main() {
struct X;
fn main() {
static S: X = X;
- let s = S;
- //^ error: cannot move `X` out of reference
+ let _s = S;
+ //^^ error: cannot move `X` out of reference
}
"#,
);
@@ -165,7 +167,7 @@ enum X {
fn main() {
let x = &X::Bar;
- let c = || match *x {
+ let _c = || match *x {
X::Foo(t) => t,
_ => 5,
};
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index d056e5c85c..ee096a100a 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -324,6 +324,7 @@ fn main() {
let x_own = 2;
let ref mut x_ref = x_own;
//^^^^^^^^^^^^^ 💡 error: cannot mutate immutable variable `x_own`
+ _ = x_ref;
}
"#,
);
@@ -331,7 +332,7 @@ fn main() {
r#"
struct Foo;
impl Foo {
- fn method(&mut self, x: i32) {}
+ fn method(&mut self, _x: i32) {}
}
fn main() {
let x = Foo;
@@ -391,6 +392,7 @@ fn main() {
//^^^^^ 💡 warn: variable does not need to be mutable
x = 7;
//^^^^^ 💡 error: cannot mutate immutable variable `x`
+ _ = y;
}
}
}
@@ -404,12 +406,14 @@ fn main() {
// there would be no mutability error for locals in dead code. Rustc tries to
// not emit `unused_mut` in this case, but since it works without `mut`, and
// special casing it is not trivial, we emit it.
+
+ // Update: now MIR based `unused-variable` is taking over `unused-mut` for the same reason.
check_diagnostics(
r#"
fn main() {
return;
let mut x = 2;
- //^^^^^ 💡 warn: variable does not need to be mutable
+ //^^^^^ warn: unused variable
&mut x;
}
"#,
@@ -419,7 +423,7 @@ fn main() {
fn main() {
loop {}
let mut x = 2;
- //^^^^^ 💡 warn: variable does not need to be mutable
+ //^^^^^ warn: unused variable
&mut x;
}
"#,
@@ -440,7 +444,7 @@ fn main(b: bool) {
g();
}
let mut x = 2;
- //^^^^^ 💡 warn: variable does not need to be mutable
+ //^^^^^ warn: unused variable
&mut x;
}
"#,
@@ -454,7 +458,7 @@ fn main(b: bool) {
return;
}
let mut x = 2;
- //^^^^^ 💡 warn: variable does not need to be mutable
+ //^^^^^ warn: unused variable
&mut x;
}
"#,
@@ -536,6 +540,7 @@ fn main() {
(k @ 5, ref mut t) if { continue; } => {
//^^^^^^^^^ 💡 error: cannot mutate immutable variable `z`
*t = 5;
+ _ = k;
}
_ => {
let y = (1, 2);
@@ -588,6 +593,7 @@ fn main() {
b = 1;
c = (2, 3);
d = 3;
+ _ = (c, b, d);
}
}
"#,
@@ -600,6 +606,7 @@ fn main() {
r#"
fn f(mut x: i32) {
//^^^^^ 💡 warn: variable does not need to be mutable
+ f(x + 2);
}
"#,
);
@@ -615,8 +622,11 @@ fn f(x: i32) {
r#"
fn f((x, y): (i32, i32)) {
let t = [0; 2];
- x = 5;
- //^^^^^ 💡 error: cannot mutate immutable variable `x`
+ x = 5;
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
+ _ = x;
+ _ = y;
+ _ = t;
}
"#,
);
@@ -645,6 +655,7 @@ fn f(x: [(i32, u8); 10]) {
//^^^^^ 💡 warn: variable does not need to be mutable
a = 2;
//^^^^^ 💡 error: cannot mutate immutable variable `a`
+ _ = b;
}
}
"#,
@@ -666,6 +677,7 @@ fn f(x: [(i32, u8); 10]) {
//^^^^^ 💡 error: cannot mutate immutable variable `a`
c = 2;
//^^^^^ 💡 error: cannot mutate immutable variable `c`
+ _ = (b, d);
}
}
}
@@ -696,18 +708,18 @@ fn f() {
fn overloaded_index() {
check_diagnostics(
r#"
-//- minicore: index
+//- minicore: index, copy
use core::ops::{Index, IndexMut};
struct Foo;
impl Index<usize> for Foo {
type Output = (i32, u8);
- fn index(&self, index: usize) -> &(i32, u8) {
+ fn index(&self, _index: usize) -> &(i32, u8) {
&(5, 2)
}
}
impl IndexMut<usize> for Foo {
- fn index_mut(&mut self, index: usize) -> &mut (i32, u8) {
+ fn index_mut(&mut self, _index: usize) -> &mut (i32, u8) {
&mut (5, 2)
}
}
@@ -715,26 +727,32 @@ fn f() {
let mut x = Foo;
//^^^^^ 💡 warn: variable does not need to be mutable
let y = &x[2];
+ _ = (x, y);
let x = Foo;
let y = &mut x[2];
//^💡 error: cannot mutate immutable variable `x`
+ _ = (x, y);
let mut x = &mut Foo;
//^^^^^ 💡 warn: variable does not need to be mutable
let y: &mut (i32, u8) = &mut x[2];
+ _ = (x, y);
let x = Foo;
let ref mut y = x[7];
//^ 💡 error: cannot mutate immutable variable `x`
+ _ = (x, y);
let (ref mut y, _) = x[3];
//^ 💡 error: cannot mutate immutable variable `x`
+ _ = y;
match x[10] {
//^ 💡 error: cannot mutate immutable variable `x`
- (ref y, _) => (),
- (_, ref mut y) => (),
+ (ref y, 5) => _ = y,
+ (_, ref mut y) => _ = y,
}
let mut x = Foo;
let mut i = 5;
//^^^^^ 💡 warn: variable does not need to be mutable
let y = &mut x[i];
+ _ = y;
}
"#,
);
@@ -744,7 +762,7 @@ fn f() {
fn overloaded_deref() {
check_diagnostics(
r#"
-//- minicore: deref_mut
+//- minicore: deref_mut, copy
use core::ops::{Deref, DerefMut};
struct Foo;
@@ -763,21 +781,27 @@ fn f() {
let mut x = Foo;
//^^^^^ 💡 warn: variable does not need to be mutable
let y = &*x;
+ _ = (x, y);
let x = Foo;
let y = &mut *x;
//^^ 💡 error: cannot mutate immutable variable `x`
+ _ = (x, y);
let x = Foo;
+ //^ warn: unused variable
let x = Foo;
let y: &mut (i32, u8) = &mut x;
//^^^^^^ 💡 error: cannot mutate immutable variable `x`
+ _ = (x, y);
let ref mut y = *x;
//^^ 💡 error: cannot mutate immutable variable `x`
+ _ = y;
let (ref mut y, _) = *x;
//^^ 💡 error: cannot mutate immutable variable `x`
+ _ = y;
match *x {
//^^ 💡 error: cannot mutate immutable variable `x`
- (ref y, _) => (),
- (_, ref mut y) => (),
+ (ref y, 5) => _ = y,
+ (_, ref mut y) => _ = y,
}
}
"#,
@@ -866,6 +890,7 @@ pub fn test() {
data: 0
}
);
+ _ = tree;
}
"#,
);
@@ -925,6 +950,7 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
let x = X;
let closure4 = || { x.mutate(); };
//^ 💡 error: cannot mutate immutable variable `x`
+ _ = (closure2, closure3, closure4);
}
"#,
);
@@ -941,7 +967,9 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
z = 3;
let mut k = z;
//^^^^^ 💡 warn: variable does not need to be mutable
+ _ = k;
};
+ _ = (x, closure);
}
"#,
);
@@ -958,6 +986,7 @@ fn f() {
}
}
};
+ _ = closure;
}
"#,
);
@@ -972,7 +1001,8 @@ fn f() {
let mut x = X;
let c2 = || { x = X; x };
let mut x = X;
- let c2 = move || { x = X; };
+ let c3 = move || { x = X; };
+ _ = (c1, c2, c3);
}
"#,
);
@@ -1023,7 +1053,7 @@ fn x(t: &[u8]) {
a = 2;
//^^^^^ 💡 error: cannot mutate immutable variable `a`
-
+ _ = b;
}
_ => {}
}
@@ -1079,6 +1109,7 @@ fn f() {
let x = Box::new(5);
let closure = || *x = 2;
//^ 💡 error: cannot mutate immutable variable `x`
+ _ = closure;
}
"#,
);
@@ -1156,6 +1187,7 @@ macro_rules! mac {
fn main2() {
let mut x = mac![];
//^^^^^ 💡 warn: variable does not need to be mutable
+ _ = x;
}
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 083ef3e8dc..d15233d15c 100644
--- a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -74,8 +74,8 @@ mod tests {
r#"
//- minicore: iterators
fn foo() {
- let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
-} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
+ let _m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
+} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
"#,
);
}
@@ -117,7 +117,7 @@ fn foo() {
fn foo() {
let mut m = core::iter::repeat(())
.filter_map(|()| Some(92));
- let n = m.next();
+ let _n = m.next();
}
"#,
);
@@ -148,22 +148,22 @@ fn foo() {
fn foo() {
#[allow(clippy::filter_map_next)]
- let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
+ let _m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
}
#[deny(clippy::filter_map_next)]
fn foo() {
- let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
-} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: replace filter_map(..).next() with find_map(..)
+ let _m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
+} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: replace filter_map(..).next() with find_map(..)
fn foo() {
- let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
-} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
+ let _m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
+} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
#[warn(clippy::filter_map_next)]
fn foo() {
- let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
-} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warn: replace filter_map(..).next() with find_map(..)
+ let _m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
+} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warn: replace filter_map(..).next() with find_map(..)
"#,
);
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 15bd28c00d..1f400bb42d 100644
--- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -205,7 +205,7 @@ fn main() {
test(123);
//^^^ 💡 error: expected &i32, found i32
}
-fn test(arg: &i32) {}
+fn test(_arg: &i32) {}
"#,
);
}
@@ -217,13 +217,13 @@ fn test(arg: &i32) {}
fn main() {
test(123$0);
}
-fn test(arg: &i32) {}
+fn test(_arg: &i32) {}
"#,
r#"
fn main() {
test(&123);
}
-fn test(arg: &i32) {}
+fn test(_arg: &i32) {}
"#,
);
}
@@ -235,13 +235,13 @@ fn test(arg: &i32) {}
fn main() {
test($0123);
}
-fn test(arg: &mut i32) {}
+fn test(_arg: &mut i32) {}
"#,
r#"
fn main() {
test(&mut 123);
}
-fn test(arg: &mut i32) {}
+fn test(_arg: &mut i32) {}
"#,
);
}
@@ -254,13 +254,13 @@ fn test(arg: &mut i32) {}
fn main() {
test($0[1, 2, 3]);
}
-fn test(arg: &[i32]) {}
+fn test(_arg: &[i32]) {}
"#,
r#"
fn main() {
test(&[1, 2, 3]);
}
-fn test(arg: &[i32]) {}
+fn test(_arg: &[i32]) {}
"#,
);
}
@@ -279,7 +279,7 @@ impl core::ops::Deref for Foo {
fn main() {
test($0Foo);
}
-fn test(arg: &Bar) {}
+fn test(_arg: &Bar) {}
"#,
r#"
struct Foo;
@@ -291,7 +291,7 @@ impl core::ops::Deref for Foo {
fn main() {
test(&Foo);
}
-fn test(arg: &Bar) {}
+fn test(_arg: &Bar) {}
"#,
);
}
@@ -305,7 +305,7 @@ fn main() {
}
struct Test;
impl Test {
- fn call_by_ref(&self, arg: &i32) {}
+ fn call_by_ref(&self, _arg: &i32) {}
}
"#,
r#"
@@ -314,7 +314,7 @@ fn main() {
}
struct Test;
impl Test {
- fn call_by_ref(&self, arg: &i32) {}
+ fn call_by_ref(&self, _arg: &i32) {}
}
"#,
);
@@ -345,7 +345,7 @@ macro_rules! thousand {
1000_u64
};
}
-fn test(foo: &u64) {}
+fn test(_foo: &u64) {}
fn main() {
test($0thousand!());
}
@@ -356,7 +356,7 @@ macro_rules! thousand {
1000_u64
};
}
-fn test(foo: &u64) {}
+fn test(_foo: &u64) {}
fn main() {
test(&thousand!());
}
@@ -369,12 +369,12 @@ fn main() {
check_fix(
r#"
fn main() {
- let test: &mut i32 = $0123;
+ let _test: &mut i32 = $0123;
}
"#,
r#"
fn main() {
- let test: &mut i32 = &mut 123;
+ let _test: &mut i32 = &mut 123;
}
"#,
);
@@ -411,7 +411,7 @@ fn div(x: i32, y: i32) -> Option<i32> {
fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
loop {}
}
- fn run(t: Rate<5>) {
+ fn run(_t: Rate<5>) {
}
fn main() {
run(f()) // FIXME: remove this error
@@ -426,7 +426,7 @@ fn div(x: i32, y: i32) -> Option<i32> {
check_diagnostics(
r#"
pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
- fn run(t: Rate<u32, 1, 1>) {
+ fn run(_t: Rate<u32, 1, 1>) {
}
fn main() {
run(Rate::<_, _, _>(5));
@@ -650,7 +650,7 @@ fn h() {
r#"
struct X<T>(T);
-fn foo(x: X<Unknown>) {}
+fn foo(_x: X<Unknown>) {}
fn test1() {
// Unknown might be `i32`, so we should not emit type mismatch here.
foo(X(42));
diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 4af6722711..4e215a89d7 100644
--- a/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -142,8 +142,8 @@ fn t<T>() -> T { loop {} }
check_diagnostics(
r#"
fn main() {
- let x = [(); _];
- let y: [(); 10] = [(); _];
+ let _x = [(); _];
+ let _y: [(); 10] = [(); _];
_ = 0;
(_,) = (1,);
}
diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs
new file mode 100644
index 0000000000..2658f12f8a
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -0,0 +1,110 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: unused-variables
+//
+// This diagnostic is triggered when a local variable is not used.
+pub(crate) fn unused_variables(
+ ctx: &DiagnosticsContext<'_>,
+ d: &hir::UnusedVariable,
+) -> Diagnostic {
+ let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
+ Diagnostic::new_with_syntax_node_ptr(
+ ctx,
+ DiagnosticCode::RustcLint("unused_variables"),
+ "unused variable",
+ ast,
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_diagnostics;
+
+ #[test]
+ fn unused_variables_simple() {
+ check_diagnostics(
+ r#"
+//- minicore: fn
+struct Foo { f1: i32, f2: i64 }
+
+fn f(kkk: i32) {}
+ //^^^ warn: unused variable
+fn main() {
+ let a = 2;
+ //^ warn: unused variable
+ let b = 5;
+ // note: `unused variable` implies `unused mut`, so we should not emit both at the same time.
+ let mut c = f(b);
+ //^^^^^ warn: unused variable
+ let (d, e) = (3, 5);
+ //^ warn: unused variable
+ let _ = e;
+ let f1 = 2;
+ let f2 = 5;
+ let f = Foo { f1, f2 };
+ match f {
+ Foo { f1, f2 } => {
+ //^^ warn: unused variable
+ _ = f2;
+ }
+ }
+ let g = false;
+ if g {}
+ let h: fn() -> i32 = || 2;
+ let i = h();
+ //^ warn: unused variable
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unused_self() {
+ check_diagnostics(
+ r#"
+struct S {
+}
+impl S {
+ fn owned_self(self, u: i32) {}
+ //^ warn: unused variable
+ fn ref_self(&self, u: i32) {}
+ //^ warn: unused variable
+ fn ref_mut_self(&mut self, u: i32) {}
+ //^ warn: unused variable
+ fn owned_mut_self(mut self) {}
+ //^^^^^^^^ 💡 warn: variable does not need to be mutable
+
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn allow_unused_variables_for_identifiers_starting_with_underline() {
+ check_diagnostics(
+ r#"
+fn main() {
+ let _x = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn respect_lint_attributes_for_unused_variables() {
+ check_diagnostics(
+ r#"
+fn main() {
+ #[allow(unused_variables)]
+ let x = 2;
+}
+
+#[deny(unused)]
+fn main2() {
+ let x = 2;
+ //^ error: unused variable
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index ebe197a679..fe5567544e 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -56,6 +56,7 @@ mod handlers {
pub(crate) mod unresolved_proc_macro;
pub(crate) mod undeclared_label;
pub(crate) mod unreachable_label;
+ pub(crate) mod unused_variables;
// The handlers below are unusual, the implement the diagnostics as well.
pub(crate) mod field_shorthand;
@@ -368,6 +369,7 @@ pub fn diagnostics(
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
+ AnyDiagnostic::UnusedVariable(d) => handlers::unused_variables::unused_variables(&ctx, &d),
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
AnyDiagnostic::MismatchedTupleStructPatArgCount(d) => handlers::mismatched_arg_count::mismatched_tuple_struct_pat_arg_count(&ctx, &d),
};
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 12e46c0f88..4152e60675 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -484,7 +484,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 10752..10760,
},
),
tooltip: "",
@@ -497,7 +497,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 10784..10788,
},
),
tooltip: "",
@@ -522,7 +522,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 10752..10760,
},
),
tooltip: "",
@@ -535,7 +535,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 10784..10788,
},
),
tooltip: "",
@@ -560,7 +560,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10739..10747,
+ range: 10752..10760,
},
),
tooltip: "",
@@ -573,7 +573,7 @@ fn main() {
file_id: FileId(
1,
),
- range: 10771..10775,
+ range: 10784..10788,
},
),
tooltip: "",
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 573f56b003..cc41d87f5d 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -489,7 +489,7 @@ pub mod ops {
I: SliceIndex<[T]>,
{
type Output = I::Output;
- fn index(&self, index: I) -> &I::Output {
+ fn index(&self, _index: I) -> &I::Output {
loop {}
}
}
@@ -497,7 +497,7 @@ pub mod ops {
where
I: SliceIndex<[T]>,
{
- fn index_mut(&mut self, index: I) -> &mut I::Output {
+ fn index_mut(&mut self, _index: I) -> &mut I::Output {
loop {}
}
}
@@ -507,7 +507,7 @@ pub mod ops {
I: SliceIndex<[T]>,
{
type Output = I::Output;
- fn index(&self, index: I) -> &I::Output {
+ fn index(&self, _index: I) -> &I::Output {
loop {}
}
}
@@ -515,7 +515,7 @@ pub mod ops {
where
I: SliceIndex<[T]>,
{
- fn index_mut(&mut self, index: I) -> &mut I::Output {
+ fn index_mut(&mut self, _index: I) -> &mut I::Output {
loop {}
}
}
@@ -863,17 +863,17 @@ pub mod fmt {
pub struct DebugTuple;
pub struct DebugStruct;
impl Formatter<'_> {
- pub fn debug_tuple(&mut self, name: &str) -> DebugTuple {
+ pub fn debug_tuple(&mut self, _name: &str) -> DebugTuple {
DebugTuple
}
- pub fn debug_struct(&mut self, name: &str) -> DebugStruct {
+ pub fn debug_struct(&mut self, _name: &str) -> DebugStruct {
DebugStruct
}
}
impl DebugTuple {
- pub fn field(&mut self, value: &dyn Debug) -> &mut Self {
+ pub fn field(&mut self, _value: &dyn Debug) -> &mut Self {
self
}
@@ -883,7 +883,7 @@ pub mod fmt {
}
impl DebugStruct {
- pub fn field(&mut self, name: &str, value: &dyn Debug) -> &mut Self {
+ pub fn field(&mut self, _name: &str, _value: &dyn Debug) -> &mut Self {
self
}
@@ -996,7 +996,7 @@ pub mod fmt {
($($t:ty)*) => {
$(
impl const Debug for $t {
- fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ fn fmt(&self, _f: &mut Formatter<'_>) -> Result {
Ok(())
}
}
@@ -1012,7 +1012,7 @@ pub mod fmt {
}
impl<T: Debug> Debug for [T] {
- fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ fn fmt(&self, _f: &mut Formatter<'_>) -> Result {
Ok(())
}
}
@@ -1062,7 +1062,7 @@ pub mod option {
}
}
- pub fn and<U>(self, optb: Option<U>) -> Option<U> {
+ pub fn and<U>(self, _optb: Option<U>) -> Option<U> {
loop {}
}
pub fn unwrap_or(self, default: T) -> T {
@@ -1080,25 +1080,25 @@ pub mod option {
}
// endregion:result
// region:fn
- pub fn and_then<U, F>(self, f: F) -> Option<U>
+ pub fn and_then<U, F>(self, _f: F) -> Option<U>
where
F: FnOnce(T) -> Option<U>,
{
loop {}
}
- pub fn unwrap_or_else<F>(self, f: F) -> T
+ pub fn unwrap_or_else<F>(self, _f: F) -> T
where
F: FnOnce() -> T,
{
loop {}
}
- pub fn map_or<U, F>(self, default: U, f: F) -> U
+ pub fn map_or<U, F>(self, _default: U, _f: F) -> U
where
F: FnOnce(T) -> U,
{
loop {}
}
- pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+ pub fn map_or_else<U, D, F>(self, _default: D, _f: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(T) -> U,
@@ -1129,7 +1129,7 @@ pub mod pin {
pointer: P,
}
impl<P> Pin<P> {
- pub fn new(pointer: P) -> Pin<P> {
+ pub fn new(_pointer: P) -> Pin<P> {
loop {}
}
}
@@ -1226,7 +1226,7 @@ pub mod iter {
mod sources {
mod repeat {
- pub fn repeat<T>(elt: T) -> Repeat<T> {
+ pub fn repeat<T>(_elt: T) -> Repeat<T> {
loop {}
}
@@ -1266,7 +1266,7 @@ pub mod iter {
fn take(self, n: usize) -> crate::iter::Take<Self> {
loop {}
}
- fn filter_map<B, F>(self, f: F) -> crate::iter::FilterMap<Self, F>
+ fn filter_map<B, F>(self, _f: F) -> crate::iter::FilterMap<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
@@ -1337,7 +1337,7 @@ mod panic {
mod panicking {
#[lang = "panic_fmt"]
- pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
+ pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! {
loop {}
}
}