Detect when attribute is provided by missing derive macro

```
error: cannot find attribute `empty_helper` in this scope
  --> $DIR/derive-helper-legacy-limits.rs:17:3
   |
LL | #[empty_helper]
   |   ^^^^^^^^^^^^
   |
help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
   |
LL + #[derive(Empty)]
LL | struct S2;
   |
```

Look at proc-macro attributes when encountering unknown attribute

```
error: cannot find attribute `sede` in this scope
  --> src/main.rs:18:7
   |
18 |     #[sede(untagged)]
   |       ^^^^
   |
help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
   |
18 |     #[serde(untagged)]
   |       ~~~~~

error: cannot find attribute `serde` in this scope
  --> src/main.rs:12:7
   |
12 |     #[serde(untagged)]
   |       ^^^^^
   |
   = note: `serde` is in scope, but it is a crate, not an attribute
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
   |
10 | #[derive(Serialize, Deserialize)]
   |
```
This commit is contained in:
Esteban Küber
2024-12-28 02:19:35 +00:00
parent 6c8138de8f
commit 92a798dac0
16 changed files with 418 additions and 7 deletions

View File

@@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel;
use rustc_data_structures::intern::Interned;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
use rustc_expand::base::{
DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind,
Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
SyntaxExtensionKind,
};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{
@@ -294,6 +295,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
&& self.tcx.def_kind(mod_def_id) == DefKind::Mod
})
.map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id);
let sugg_span = match &invoc.kind {
InvocationKind::Attr { item: Annotatable::Item(item), .. }
if !item.span.from_expansion() =>
{
Some(item.span.shrink_to_lo())
}
_ => None,
};
let (ext, res) = self.smart_resolve_macro_path(
path,
kind,
@@ -304,6 +313,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
force,
deleg_impl,
looks_like_invoc_in_mod_inert_attr,
sugg_span,
)?;
let span = invoc.span();
@@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
true,
force,
None,
None,
) {
Ok((Some(ext), _)) => {
if !ext.helper_attrs.is_empty() {
@@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
force: bool,
deleg_impl: Option<LocalDefId>,
invoc_in_mod_inert_attr: Option<LocalDefId>,
suggestion_span: Option<Span>,
) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_or_delegation_path(
path,
@@ -538,6 +550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
deleg_impl,
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
None,
suggestion_span,
) {
Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
trace: bool,
force: bool,
ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
self.resolve_macro_or_delegation_path(
path,
@@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None,
None,
ignore_import,
suggestion_span,
)
}
@@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
deleg_impl: Option<LocalDefId>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
ignore_import: Option<Import<'ra>>,
suggestion_span: Option<Span>,
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
let path_span = ast_path.span;
let mut path = Segment::from_path(ast_path);
@@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
kind,
*parent_scope,
binding.ok(),
suggestion_span,
));
}
@@ -905,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions);
for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions {
match self.early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::Macro(kind),
@@ -946,7 +963,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
expected,
ident,
});
self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate);
self.unresolved_macro_suggestions(
&mut err,
kind,
&parent_scope,
ident,
krate,
sugg_span,
);
err.emit();
}
}