Fix many false negatives caused by autoderef

This commit is contained in:
Sosthène Guédon 2022-11-20 17:03:53 +01:00
parent 0411edfbbd
commit 1f2f50c34e
3 changed files with 77 additions and 39 deletions

View File

@ -6,6 +6,8 @@
use rustc_middle::ty;
use rustc_span::Span;
use std::iter;
use super::MISNAMED_GETTERS;
pub fn check_fn(
@ -75,39 +77,35 @@ pub fn check_fn(
}
};
let ty = cx.typeck_results().expr_ty_adjusted(self_data);
let def = {
let mut kind = ty.kind();
loop {
match kind {
ty::Adt(def, _) => break def,
ty::Ref(_, ty, _) => kind = ty.kind(),
// We don't do tuples because the function name cannot be a number
_ => return,
}
}
};
let mut used_field = None;
let mut correct_field = None;
for f in def.all_fields() {
if f.name.as_str() == name {
correct_field = Some(f);
}
if f.name == used_ident.name {
used_field = Some(f);
let typeck_results = cx.typeck_results();
for adjusted_type in iter::once(typeck_results.expr_ty(self_data))
.chain(typeck_results.expr_adjustments(self_data).iter().map(|adj| adj.target))
{
let ty::Adt(def,_) = adjusted_type.kind() else {
continue;
};
for f in def.all_fields() {
if f.name.as_str() == name {
correct_field = Some(f);
}
if f.name == used_ident.name {
used_field = Some(f);
}
}
}
let Some(used_field) = used_field else {
// FIXME: This can be reached if the field access uses autoderef.
// `dec.all_fields()` should be replaced by something that uses autoderef on the unajusted type of `self_data`
// Can happen if the field access is a tuple. We don't lint those because the getter name could not start with a number.
return;
};
let Some(correct_field) = correct_field else {
return;
// There is no field corresponding to the getter name.
// FIXME: This can be a false positive if the correct field is reachable trought deeper autodereferences than used_field is
return;
};
if cx.tcx.type_of(used_field.did) == cx.tcx.type_of(correct_field.did) {

View File

@ -85,15 +85,37 @@ unsafe fn c_unchecked_mut(&mut self) -> &mut u8 {
}
}
struct C {
inner: Box<A>,
struct D {
d: u8,
inner: A,
}
impl C {
unsafe fn a(&self) -> &u8 {
&self.inner.b
impl core::ops::Deref for D {
type Target = A;
fn deref(&self) -> &A {
&self.inner
}
unsafe fn a_mut(&mut self) -> &mut u8 {
&mut self.inner.b
}
impl core::ops::DerefMut for D {
fn deref_mut(&mut self) -> &mut A {
&mut self.inner
}
}
impl D {
fn a(&self) -> &u8 {
&self.b
}
fn a_mut(&mut self) -> &mut u8 {
&mut self.b
}
fn d(&self) -> &u8 {
&self.b
}
fn d_mut(&mut self) -> &mut u8 {
&mut self.b
}
}

View File

@ -127,22 +127,40 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
--> $DIR/misnamed_getters.rs:92:5
--> $DIR/misnamed_getters.rs:107:5
|
LL | / unsafe fn a(&self) -> &u8 {
LL | | &self.inner.b
| | ------------- help: consider using: `&self.inner.a`
LL | / fn a(&self) -> &u8 {
LL | | &self.b
| | ------- help: consider using: `&self.a`
LL | | }
| |_____^
error: getter function appears to return the wrong field
--> $DIR/misnamed_getters.rs:95:5
--> $DIR/misnamed_getters.rs:110:5
|
LL | / unsafe fn a_mut(&mut self) -> &mut u8 {
LL | | &mut self.inner.b
| | ----------------- help: consider using: `&mut self.inner.a`
LL | / fn a_mut(&mut self) -> &mut u8 {
LL | | &mut self.b
| | ----------- help: consider using: `&mut self.a`
LL | | }
| |_____^
error: aborting due to 16 previous errors
error: getter function appears to return the wrong field
--> $DIR/misnamed_getters.rs:114:5
|
LL | / fn d(&self) -> &u8 {
LL | | &self.b
| | ------- help: consider using: `&self.d`
LL | | }
| |_____^
error: getter function appears to return the wrong field
--> $DIR/misnamed_getters.rs:117:5
|
LL | / fn d_mut(&mut self) -> &mut u8 {
LL | | &mut self.b
| | ----------- help: consider using: `&mut self.d`
LL | | }
| |_____^
error: aborting due to 18 previous errors