use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::{Attribute, EnumDef, MetaItemInner, MetaItemKind, VariantData};
use rustc_lint::EarlyContext;
use rustc_span::{Span, Symbol, sym};
use super::PREFER_DERIVE_MORE_OVER_THISERROR;
pub(super) fn flag_error_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
let error = Symbol::intern("error");
for attr in attrs {
if attr.has_name(error) {
emit_error_attr(cx, attr.span);
} else if attr.has_name(sym::cfg_attr)
&& let Some(args) = attr.meta_item_list()
{
flag_error_in_cfg_attr_payload(cx, args.get(1..).unwrap_or(&[]), error);
}
}
}
fn flag_error_in_cfg_attr_payload(cx: &EarlyContext<'_>, items: &[MetaItemInner], error: Symbol) {
for item in items {
let Some(meta) = item.meta_item() else {
continue;
};
if meta.has_name(error) {
emit_error_attr(cx, meta.span);
} else if meta.has_name(sym::cfg_attr)
&& let MetaItemKind::List(args) = &meta.kind
{
flag_error_in_cfg_attr_payload(cx, args.get(1..).unwrap_or(&[]), error);
}
}
}
pub(super) fn flag_variant_data_error_attrs(cx: &EarlyContext<'_>, data: &VariantData) {
for field in data.fields() {
flag_error_attrs(cx, &field.attrs);
}
}
pub(super) fn flag_enum_error_attrs(cx: &EarlyContext<'_>, def: &EnumDef) {
for variant in &def.variants {
flag_error_attrs(cx, &variant.attrs);
flag_variant_data_error_attrs(cx, &variant.data);
}
}
pub(super) fn emit_use(cx: &EarlyContext<'_>, span: Span) {
span_lint_and_help(
cx,
PREFER_DERIVE_MORE_OVER_THISERROR,
span,
"`thiserror` import; this catalogue prefers `derive_more::{Display, Error}`",
None,
"drop the import and migrate the error type to `#[derive(derive_more::Display, \
derive_more::Error)]`",
);
}
pub(super) fn emit_derive(cx: &EarlyContext<'_>, span: Span) {
span_lint_and_help(
cx,
PREFER_DERIVE_MORE_OVER_THISERROR,
span,
"error type derived through `thiserror`; this catalogue prefers \
`derive_more::{Display, Error}`",
None,
"replace the derive list and migrate the `#[error(...)]` attributes to `#[display(...)]`",
);
}
fn emit_error_attr(cx: &EarlyContext<'_>, span: Span) {
span_lint_and_help(
cx,
PREFER_DERIVE_MORE_OVER_THISERROR,
span,
"`#[error(...)]` attribute belongs to `thiserror`'s namespace; this catalogue prefers \
`derive_more::Display`",
None,
"rename to `#[display(...)]` and translate positional placeholders (`{0}` -> `{_0}`)",
);
}