Skip to content

Commit 4df6cbe

Browse files
Consider privacy more carefully when suggesting accessing fields
1 parent 9cf5709 commit 4df6cbe

10 files changed

+40
-80
lines changed

compiler/rustc_typeck/src/check/expr.rs

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,15 +2535,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25352535
);
25362536

25372537
// try to add a suggestion in case the field is a nested field of a field of the Adt
2538-
if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
2539-
for candidate_field in fields.iter() {
2538+
let mod_id = self.tcx.parent_module(id).to_def_id();
2539+
if let Some((fields, substs)) =
2540+
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
2541+
{
2542+
for candidate_field in fields {
25402543
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
25412544
span,
25422545
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
25432546
candidate_field,
25442547
substs,
25452548
vec![],
2546-
self.tcx.parent_module(id).to_def_id(),
2549+
mod_id,
25472550
) {
25482551
// field_path includes `field` that we're looking for, so pop it.
25492552
field_path.pop();
@@ -2567,22 +2570,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25672570
err
25682571
}
25692572

2570-
pub(crate) fn get_field_candidates(
2573+
pub(crate) fn get_field_candidates_considering_privacy(
25712574
&self,
25722575
span: Span,
2573-
base_t: Ty<'tcx>,
2574-
) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
2575-
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
2576+
base_ty: Ty<'tcx>,
2577+
mod_id: DefId,
2578+
) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
2579+
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
25762580

2577-
for (base_t, _) in self.autoderef(span, base_t) {
2581+
for (base_t, _) in self.autoderef(span, base_ty) {
25782582
match base_t.kind() {
25792583
ty::Adt(base_def, substs) if !base_def.is_enum() => {
2580-
let fields = &base_def.non_enum_variant().fields;
2581-
// For compile-time reasons put a limit on number of fields we search
2582-
if fields.len() > 100 {
2583-
return None;
2584-
}
2585-
return Some((fields, substs));
2584+
let tcx = self.tcx;
2585+
return Some((
2586+
base_def
2587+
.non_enum_variant()
2588+
.fields
2589+
.iter()
2590+
.filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
2591+
// For compile-time reasons put a limit on number of fields we search
2592+
.take(100),
2593+
substs,
2594+
));
25862595
}
25872596
_ => {}
25882597
}
@@ -2599,7 +2608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25992608
candidate_field: &ty::FieldDef,
26002609
subst: SubstsRef<'tcx>,
26012610
mut field_path: Vec<Ident>,
2602-
id: DefId,
2611+
mod_id: DefId,
26032612
) -> Option<Vec<Ident>> {
26042613
debug!(
26052614
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2615,20 +2624,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26152624
let field_ty = candidate_field.ty(self.tcx, subst);
26162625
if matches(candidate_field, field_ty) {
26172626
return Some(field_path);
2618-
} else if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
2627+
} else if let Some((nested_fields, subst)) =
2628+
self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
2629+
{
26192630
// recursively search fields of `candidate_field` if it's a ty::Adt
26202631
for field in nested_fields {
2621-
if field.vis.is_accessible_from(id, self.tcx) {
2622-
if let Some(field_path) = self.check_for_nested_field_satisfying(
2623-
span,
2624-
matches,
2625-
field,
2626-
subst,
2627-
field_path.clone(),
2628-
id,
2629-
) {
2630-
return Some(field_path);
2631-
}
2632+
if let Some(field_path) = self.check_for_nested_field_satisfying(
2633+
span,
2634+
matches,
2635+
field,
2636+
subst,
2637+
field_path.clone(),
2638+
mod_id,
2639+
) {
2640+
return Some(field_path);
26322641
}
26332642
}
26342643
}

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,10 +1334,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13341334
item_name: Ident,
13351335
) {
13361336
if let SelfSource::MethodCall(expr) = source
1337-
&& let Some((fields, substs)) = self.get_field_candidates(span, actual)
1337+
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
1338+
&& let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
13381339
{
13391340
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
1340-
for candidate_field in fields.iter() {
1341+
for candidate_field in fields {
13411342
if let Some(field_path) = self.check_for_nested_field_satisfying(
13421343
span,
13431344
&|_, field_ty| {
@@ -1353,7 +1354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13531354
candidate_field,
13541355
substs,
13551356
vec![],
1356-
self.tcx.parent_module(expr.hir_id).to_def_id(),
1357+
mod_id,
13571358
) {
13581359
let field_path_str = field_path
13591360
.iter()

src/test/ui/issues/issue-31173.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ LL | pub struct TakeWhile<I, P> {
3333
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
3434
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
3535
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
36-
help: one of the expressions' fields has a method of the same name
37-
|
38-
LL | .it.collect();
39-
| +++
4036

4137
error: aborting due to 2 previous errors
4238

src/test/ui/issues/issue-39175.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ LL | Command::new("echo").arg("hello").exec();
55
| ^^^^ method not found in `&mut Command`
66
|
77
= help: items from traits can only be used if the trait is in scope
8-
help: one of the expressions' fields has a method of the same name
9-
|
10-
LL | Command::new("echo").arg("hello").inner.exec();
11-
| ++++++
128
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
139
|
1410
LL | use std::os::unix::process::CommandExt;

src/test/ui/mismatched_types/issue-36053-2.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ LL | pub struct Filter<I, P> {
3535
which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
3636
`Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
3737
which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
38-
help: one of the expressions' fields has a method of the same name
39-
|
40-
LL | once::<&str>("str").fuse().filter(|a: &str| true).iter.count();
41-
| +++++
4238

4339
error: aborting due to 2 previous errors
4440

src/test/ui/suggestions/import-trait-for-method-call.stderr

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ LL | fn finish(&self) -> u64;
1010
| ------ the method is available for `DefaultHasher` here
1111
|
1212
= help: items from traits can only be used if the trait is in scope
13-
help: one of the expressions' fields has a method of the same name
14-
|
15-
LL | h.0.finish()
16-
| ++
1713
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
1814
|
1915
LL | use std::hash::Hasher;

src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,6 @@ LL | pub struct BufWriter<W: Write> {
4141
`&dyn std::io::Write: std::io::Write`
4242
which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
4343
= note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
44-
help: one of the expressions' fields has a method of the same name
45-
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
46-
|
47-
LL | $dst.inner.write_fmt($crate::format_args_nl!($($arg)*))
48-
| ++++++
49-
help: one of the expressions' fields has a method of the same name
50-
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
51-
|
52-
LL | $dst.buf.write_fmt($crate::format_args_nl!($($arg)*))
53-
| ++++
5444

5545
error: aborting due to 3 previous errors
5646

src/test/ui/suggestions/suggest-using-chars.stderr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator`
2525
|
2626
LL | let _ = String::from("bar").chars();
2727
| ~~~~~
28-
help: one of the expressions' fields has a method of the same name
29-
|
30-
LL | let _ = String::from("bar").vec.iter();
31-
| ++++
3228

3329
error[E0599]: no method named `iter` found for reference `&String` in the current scope
3430
--> $DIR/suggest-using-chars.rs:5:36
@@ -40,10 +36,6 @@ help: because of the in-memory representation of `&str`, to obtain an `Iterator`
4036
|
4137
LL | let _ = (&String::from("bar")).chars();
4238
| ~~~~~
43-
help: one of the expressions' fields has a method of the same name
44-
|
45-
LL | let _ = (&String::from("bar")).vec.iter();
46-
| ++++
4739

4840
error[E0599]: no method named `iter` found for type `{integer}` in the current scope
4941
--> $DIR/suggest-using-chars.rs:6:15

src/test/ui/unique-object-noncopyable.stderr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,6 @@ LL | | >(Unique<T>, A);
2323
which is required by `Box<dyn Foo>: Clone`
2424
`dyn Foo: Clone`
2525
which is required by `Box<dyn Foo>: Clone`
26-
help: one of the expressions' fields has a method of the same name
27-
|
28-
LL | let _z = y.0.clone();
29-
| ++
30-
help: one of the expressions' fields has a method of the same name
31-
|
32-
LL | let _z = y.1.clone();
33-
| ++
3426

3527
error: aborting due to previous error
3628

src/test/ui/unique-pinned-nocopy.stderr

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ help: consider annotating `R` with `#[derive(Clone)]`
2525
|
2626
LL | #[derive(Clone)]
2727
|
28-
help: one of the expressions' fields has a method of the same name
29-
|
30-
LL | let _j = i.0.clone();
31-
| ++
32-
help: one of the expressions' fields has a method of the same name
33-
|
34-
LL | let _j = i.1.clone();
35-
| ++
3628

3729
error: aborting due to previous error
3830

0 commit comments

Comments
 (0)