mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
When encountering struct fn call literal with private fields, suggest all builders
When encountering code like `Box(42)`, suggest `Box::new(42)` and *all* other associated functions that return `-> Box<T>`.
This commit is contained in:
parent
27794f95fd
commit
42aa1273b0
@ -759,6 +759,9 @@ impl Diagnostic {
|
|||||||
suggestions: impl IntoIterator<Item = String>,
|
suggestions: impl IntoIterator<Item = String>,
|
||||||
applicability: Applicability,
|
applicability: Applicability,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
|
let mut suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||||
|
suggestions.sort();
|
||||||
|
|
||||||
self.span_suggestions_with_style(
|
self.span_suggestions_with_style(
|
||||||
sp,
|
sp,
|
||||||
msg,
|
msg,
|
||||||
@ -768,7 +771,9 @@ impl Diagnostic {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
|
/// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. This version
|
||||||
|
/// *doesn't* sort the suggestions, so the caller has control of the order in which they are
|
||||||
|
/// presented.
|
||||||
pub fn span_suggestions_with_style(
|
pub fn span_suggestions_with_style(
|
||||||
&mut self,
|
&mut self,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
@ -777,9 +782,7 @@ impl Diagnostic {
|
|||||||
applicability: Applicability,
|
applicability: Applicability,
|
||||||
style: SuggestionStyle,
|
style: SuggestionStyle,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
let mut suggestions: Vec<_> = suggestions.into_iter().collect();
|
let suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||||
suggestions.sort();
|
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
|
!(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
|
||||||
"Span must not be empty and have no suggestion"
|
"Span must not be empty and have no suggestion"
|
||||||
|
@ -442,10 +442,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
|||||||
|
|
||||||
self.formatting_init.extend(code_init);
|
self.formatting_init.extend(code_init);
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
|
let mut code: Vec<_> = #code_field.into_iter().collect();
|
||||||
|
code.sort();
|
||||||
#diag.span_suggestions_with_style(
|
#diag.span_suggestions_with_style(
|
||||||
#span_field,
|
#span_field,
|
||||||
crate::fluent_generated::#slug,
|
crate::fluent_generated::#slug,
|
||||||
#code_field,
|
code,
|
||||||
#applicability,
|
#applicability,
|
||||||
#style
|
#style
|
||||||
);
|
);
|
||||||
|
@ -2608,6 +2608,7 @@ fn show_candidates(
|
|||||||
path_strings.extend(core_path_strings);
|
path_strings.extend(core_path_strings);
|
||||||
path_strings.dedup_by(|a, b| a.0 == b.0);
|
path_strings.dedup_by(|a, b| a.0 == b.0);
|
||||||
}
|
}
|
||||||
|
accessible_path_strings.sort();
|
||||||
|
|
||||||
if !accessible_path_strings.is_empty() {
|
if !accessible_path_strings.is_empty() {
|
||||||
let (determiner, kind, name, through) =
|
let (determiner, kind, name, through) =
|
||||||
|
@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
|
|||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||||
MultiSpan,
|
MultiSpan, SuggestionStyle,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
||||||
@ -29,6 +29,8 @@ use rustc_span::hygiene::MacroKind;
|
|||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use rustc_middle::ty;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -1593,30 +1595,86 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||||||
Some(Vec::from(pattern_spans))
|
Some(Vec::from(pattern_spans))
|
||||||
}
|
}
|
||||||
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
||||||
_ if source.is_call() => {
|
PathSource::Expr(Some(Expr { kind: ExprKind::Call(_, ref args), .. })) => {
|
||||||
err.set_primary_message(
|
err.set_primary_message(
|
||||||
"cannot initialize a tuple struct which contains private fields",
|
"cannot initialize a tuple struct which contains private fields",
|
||||||
);
|
);
|
||||||
if !def_id.is_local()
|
if !def_id.is_local() {
|
||||||
&& self
|
// Look at all the associated functions without receivers in the type's
|
||||||
|
// inherent impls to look for builders that return `Self`
|
||||||
|
let mut items = self
|
||||||
.r
|
.r
|
||||||
.tcx
|
.tcx
|
||||||
.inherent_impls(def_id)
|
.inherent_impls(def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|impl_def_id| {
|
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
|
||||||
self.r.tcx.provided_trait_methods(*impl_def_id)
|
// Only assoc fn with no receivers.
|
||||||
|
.filter(|item| {
|
||||||
|
matches!(item.kind, ty::AssocKind::Fn)
|
||||||
|
&& !item.fn_has_self_parameter
|
||||||
})
|
})
|
||||||
.any(|assoc| !assoc.fn_has_self_parameter && assoc.name == sym::new)
|
.filter_map(|item| {
|
||||||
|
// Only assoc fns that return `Self`
|
||||||
|
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
|
||||||
|
let ret_ty = fn_sig.output();
|
||||||
|
let ret_ty = self.r.tcx.erase_late_bound_regions(ret_ty);
|
||||||
|
let ty::Adt(def, _args) = ret_ty.kind() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Check for `-> Self`
|
||||||
|
if def.did() == def_id {
|
||||||
|
let order = if item.name.as_str().starts_with("new")
|
||||||
|
&& fn_sig.inputs().skip_binder().len() == args.len()
|
||||||
{
|
{
|
||||||
// FIXME: look for associated functions with Self return type,
|
0
|
||||||
// instead of relying only on the name and lack of self receiver.
|
} else if item.name.as_str().starts_with("new")
|
||||||
|
|| item.name.as_str().starts_with("default")
|
||||||
|
{
|
||||||
|
// Give higher precedence to functions with a name that
|
||||||
|
// imply construction.
|
||||||
|
1
|
||||||
|
} else if fn_sig.inputs().skip_binder().len() == args.len()
|
||||||
|
{
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
};
|
||||||
|
return Some((order, item.name));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
items.sort_by_key(|(order, _)| *order);
|
||||||
|
match &items[..] {
|
||||||
|
[] => {}
|
||||||
|
[(_, name)] => {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span.shrink_to_hi(),
|
span.shrink_to_hi(),
|
||||||
"you might have meant to use the `new` associated function",
|
format!(
|
||||||
"::new".to_string(),
|
"you might have meant to use the `{name}` associated \
|
||||||
|
function",
|
||||||
|
),
|
||||||
|
format!("::{name}"),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
// We use this instead of `span_suggestions` to retain output
|
||||||
|
// sort order.
|
||||||
|
err.span_suggestions_with_style(
|
||||||
|
span.shrink_to_hi(),
|
||||||
|
"you might have meant to use an associated function to \
|
||||||
|
build this type",
|
||||||
|
items
|
||||||
|
.iter()
|
||||||
|
.map(|(_, name)| format!("::{name}"))
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
SuggestionStyle::ShowAlways,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Use spans of the tuple struct definition.
|
// Use spans of the tuple struct definition.
|
||||||
self.r.field_def_ids(def_id).map(|field_ids| {
|
self.r.field_def_ids(def_id).map(|field_ids| {
|
||||||
field_ids
|
field_ids
|
||||||
|
@ -25,8 +25,8 @@ LL | a!();
|
|||||||
| ---- in this macro invocation
|
| ---- in this macro invocation
|
||||||
|
|
|
|
||||||
= help: consider importing one of these items:
|
= help: consider importing one of these items:
|
||||||
std::mem
|
|
||||||
core::mem
|
core::mem
|
||||||
|
std::mem
|
||||||
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
|
error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
// run-rustfix
|
|
||||||
#![allow(dead_code)]
|
|
||||||
struct U <T> {
|
|
||||||
wtf: Option<Box<U<T>>>,
|
|
||||||
x: T,
|
|
||||||
}
|
|
||||||
fn main() {
|
|
||||||
U {
|
|
||||||
wtf: Some(Box::new(U { //~ ERROR cannot initialize a tuple struct which contains private fields
|
|
||||||
wtf: None,
|
|
||||||
x: (),
|
|
||||||
})),
|
|
||||||
x: ()
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
// run-rustfix
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
struct U <T> {
|
struct U <T> {
|
||||||
wtf: Option<Box<U<T>>>,
|
wtf: Option<Box<U<T>>>,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0423]: cannot initialize a tuple struct which contains private fields
|
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||||
--> $DIR/suggest-box-new.rs:9:19
|
--> $DIR/suggest-box-new.rs:8:19
|
||||||
|
|
|
|
||||||
LL | wtf: Some(Box(U {
|
LL | wtf: Some(Box(U {
|
||||||
| ^^^
|
| ^^^
|
||||||
@ -10,10 +10,17 @@ note: constructor is not visible here due to private fields
|
|||||||
= note: private field
|
= note: private field
|
||||||
|
|
|
|
||||||
= note: private field
|
= note: private field
|
||||||
help: you might have meant to use the `new` associated function
|
help: you might have meant to use an associated function to build this type
|
||||||
|
|
|
|
||||||
LL | wtf: Some(Box::new(U {
|
LL | wtf: Some(Box::new(U {
|
||||||
| +++++
|
| +++++
|
||||||
|
LL | wtf: Some(Box::new_uninit_in(U {
|
||||||
|
| +++++++++++++++
|
||||||
|
LL | wtf: Some(Box::new_zeroed_in(U {
|
||||||
|
| +++++++++++++++
|
||||||
|
LL | wtf: Some(Box::new_uninit_slice(U {
|
||||||
|
| ++++++++++++++++++
|
||||||
|
and 10 other candidates
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom`
|
|||||||
LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
|
LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
|
||||||
| ^^^^^^^ use of undeclared type `TryFrom`
|
| ^^^^^^^ use of undeclared type `TryFrom`
|
||||||
|
|
|
|
||||||
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
|
|
||||||
= note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
|
= note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
|
||||||
|
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
|
||||||
help: consider importing one of these items
|
help: consider importing one of these items
|
||||||
|
|
|
|
||||||
LL + use core::convert::TryFrom;
|
LL + use core::convert::TryFrom;
|
||||||
@ -19,8 +19,8 @@ error[E0433]: failed to resolve: use of undeclared type `TryInto`
|
|||||||
LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
|
LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
|
||||||
| ^^^^^^^ use of undeclared type `TryInto`
|
| ^^^^^^^ use of undeclared type `TryInto`
|
||||||
|
|
|
|
||||||
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
|
|
||||||
= note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
|
= note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
|
||||||
|
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
|
||||||
help: consider importing one of these items
|
help: consider importing one of these items
|
||||||
|
|
|
|
||||||
LL + use core::convert::TryInto;
|
LL + use core::convert::TryInto;
|
||||||
@ -34,8 +34,8 @@ error[E0433]: failed to resolve: use of undeclared type `FromIterator`
|
|||||||
LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
|
LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
|
||||||
| ^^^^^^^^^^^^ use of undeclared type `FromIterator`
|
| ^^^^^^^^^^^^ use of undeclared type `FromIterator`
|
||||||
|
|
|
|
||||||
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
|
|
||||||
= note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
|
= note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
|
||||||
|
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
|
||||||
help: a trait with a similar name exists
|
help: a trait with a similar name exists
|
||||||
|
|
|
|
||||||
LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]);
|
LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]);
|
||||||
|
Loading…
Reference in New Issue
Block a user