Detect missing derive on unresolved attribute even when not imported
```
error: cannot find attribute `sede` in this scope
--> $DIR/missing-derive-3.rs:20:7
|
LL | #[sede(untagged)]
| ^^^^
|
help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
|
LL | #[serde(untagged)]
| +
error: cannot find attribute `serde` in this scope
--> $DIR/missing-derive-3.rs:14:7
|
LL | #[serde(untagged)]
| ^^^^^
|
note: `serde` is imported here, but it is a crate, not an attribute
--> $DIR/missing-derive-3.rs:4:1
|
LL | extern crate serde;
| ^^^^^^^^^^^^^^^^^^^
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
LL | enum B {
|
```
This commit is contained in:
parent
c018ae5389
commit
8baab4cdf7
7 changed files with 60 additions and 27 deletions
|
|
@ -32,6 +32,7 @@ use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateS
|
|||
use rustc_session::lint::{self, BuiltinLintDiag};
|
||||
use rustc_session::output::validate_crate_name;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
||||
use rustc_target::spec::{PanicStrategy, Target};
|
||||
|
|
@ -275,6 +276,10 @@ impl CStore {
|
|||
.filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
|
||||
}
|
||||
|
||||
pub fn all_proc_macro_def_ids(&self) -> impl Iterator<Item = DefId> {
|
||||
self.iter_crate_data().flat_map(|(krate, data)| data.proc_macros_for_crate(krate, self))
|
||||
}
|
||||
|
||||
fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
|
||||
if !deps.contains(&cnum) {
|
||||
let data = self.get_crate_data(cnum);
|
||||
|
|
|
|||
|
|
@ -2014,6 +2014,22 @@ impl CrateMetadata {
|
|||
self.root.is_proc_macro_crate()
|
||||
}
|
||||
|
||||
pub(crate) fn proc_macros_for_crate(
|
||||
&self,
|
||||
krate: CrateNum,
|
||||
cstore: &CStore,
|
||||
) -> impl Iterator<Item = DefId> {
|
||||
gen move {
|
||||
for def_id in self.root.proc_macro_data.as_ref().into_iter().flat_map(move |data| {
|
||||
data.macros
|
||||
.decode(CrateMetadataRef { cdata: self, cstore })
|
||||
.map(move |index| DefId { index, krate })
|
||||
}) {
|
||||
yield def_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn name(&self) -> Symbol {
|
||||
self.root.header.name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,6 +210,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Add every proc macro accessible from the current crate to the `macro_map` so diagnostics can
|
||||
/// find them for suggestions.
|
||||
pub(crate) fn register_macros_for_all_crates(&mut self) {
|
||||
if !self.all_crate_macros_already_registered {
|
||||
for def_id in self.cstore().all_proc_macro_def_ids() {
|
||||
self.get_macro_by_def_id(def_id);
|
||||
}
|
||||
self.all_crate_macros_already_registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_reduced_graph(
|
||||
&mut self,
|
||||
fragment: &AstFragment,
|
||||
|
|
|
|||
|
|
@ -1469,33 +1469,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
krate: &Crate,
|
||||
sugg_span: Option<Span>,
|
||||
) {
|
||||
// Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
|
||||
// for suggestions.
|
||||
self.cm().visit_scopes(
|
||||
ScopeSet::Macro(MacroKind::Derive),
|
||||
&parent_scope,
|
||||
ident.span.ctxt(),
|
||||
|this, scope, _use_prelude, _ctxt| {
|
||||
let Scope::Module(m, _) = scope else {
|
||||
return None;
|
||||
};
|
||||
for (_, resolution) in this.resolutions(m).borrow().iter() {
|
||||
let Some(binding) = resolution.borrow().best_binding() else {
|
||||
continue;
|
||||
};
|
||||
let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else {
|
||||
continue;
|
||||
};
|
||||
if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) {
|
||||
continue;
|
||||
}
|
||||
// By doing this all *imported* macros get added to the `macro_map` even if they
|
||||
// are *unused*, which makes the later suggestions find them and work.
|
||||
let _ = this.get_macro_by_def_id(def_id);
|
||||
}
|
||||
None::<()>
|
||||
},
|
||||
);
|
||||
// Bring all unused `derive` macros into `macro_map` so we ensure they can be used for
|
||||
// suggestions.
|
||||
self.register_macros_for_all_crates();
|
||||
|
||||
let is_expected =
|
||||
&|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
|
||||
|
|
|
|||
|
|
@ -1267,6 +1267,10 @@ pub struct Resolver<'ra, 'tcx> {
|
|||
|
||||
mods_with_parse_errors: FxHashSet<DefId>,
|
||||
|
||||
/// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we
|
||||
/// don't need to run it more than once.
|
||||
all_crate_macros_already_registered: bool = false,
|
||||
|
||||
// Stores pre-expansion and pre-placeholder-fragment-insertion names for `impl Trait` types
|
||||
// that were encountered during resolution. These names are used to generate item names
|
||||
// for APITs, so we don't want to leak details of resolution into these names.
|
||||
|
|
|
|||
|
|
@ -559,6 +559,12 @@ error: cannot find attribute `error` in this scope
|
|||
|
|
||||
LL | #[error(no_crate_example, code = E0123)]
|
||||
| ^^^^^
|
||||
|
|
||||
help: `error` is an attribute that can be used by the derive macro `Error`, you might be missing a `derive` attribute
|
||||
|
|
||||
LL + #[derive(Error)]
|
||||
LL | struct ErrorAttribute {}
|
||||
|
|
||||
|
||||
error: cannot find attribute `warn_` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:590:3
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ error: cannot find attribute `sede` in this scope
|
|||
|
|
||||
LL | #[sede(untagged)]
|
||||
| ^^^^
|
||||
|
|
||||
help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
|
||||
|
|
||||
LL | #[serde(untagged)]
|
||||
| +
|
||||
|
||||
error: cannot find attribute `serde` in this scope
|
||||
--> $DIR/missing-derive-3.rs:14:7
|
||||
|
|
@ -15,6 +20,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
|
|||
|
|
||||
LL | extern crate serde;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
||||
|
|
||||
LL + #[derive(Deserialize, Serialize)]
|
||||
LL | enum B {
|
||||
|
|
||||
|
||||
error: cannot find attribute `serde` in this scope
|
||||
--> $DIR/missing-derive-3.rs:6:3
|
||||
|
|
@ -27,6 +37,11 @@ note: `serde` is imported here, but it is a crate, not an attribute
|
|||
|
|
||||
LL | extern crate serde;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
||||
|
|
||||
LL + #[derive(Deserialize, Serialize)]
|
||||
LL | enum A {
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue