mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-02 18:27:37 +00:00
take attr style into account in attr diagnostics
This commit is contained in:
parent
1ae7c49072
commit
70e26c1b7b
@ -62,8 +62,8 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions =
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "inline");
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||
return None;
|
||||
|
@ -107,7 +107,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use);
|
||||
let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use);
|
||||
cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
|
@ -35,8 +35,8 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
||||
Some(value_str)
|
||||
}
|
||||
ArgParser::List(_) => {
|
||||
let suggestions =
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "must_use");
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "must_use");
|
||||
cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
|
@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
ArgParser::NameValue(name_value) => {
|
||||
let Some(str_value) = name_value.value_as_str() else {
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(false, "ignore");
|
||||
.suggestions(cx.attr_style, "ignore");
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions },
|
||||
@ -40,8 +40,8 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
Some(str_value)
|
||||
}
|
||||
ArgParser::List(_) => {
|
||||
let suggestions =
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "ignore");
|
||||
let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
|
||||
.suggestions(cx.attr_style, "ignore");
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
|
||||
return None;
|
||||
|
@ -5,7 +5,7 @@ use std::sync::LazyLock;
|
||||
|
||||
use itertools::Itertools;
|
||||
use private::Sealed;
|
||||
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
|
||||
use rustc_ast::{self as ast, AttrStyle, LitKind, MetaItemLit, NodeId};
|
||||
use rustc_errors::{DiagCtxtHandle, Diagnostic};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
@ -313,6 +313,7 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
/// The span of the attribute currently being parsed
|
||||
pub(crate) attr_span: Span,
|
||||
|
||||
pub(crate) attr_style: AttrStyle,
|
||||
/// The expected structure of the attribute.
|
||||
///
|
||||
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
|
||||
@ -394,6 +395,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
||||
}),
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -404,6 +406,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedIntegerLiteral,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -414,6 +417,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedList,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -424,6 +428,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedNoArgs,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -435,6 +440,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedIdentifier,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -447,6 +453,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedNameValue(name),
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -458,6 +465,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::DuplicateKey(key),
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -470,6 +478,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::UnexpectedLiteral,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -480,6 +489,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSingleArgument,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -490,6 +500,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -508,6 +519,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: false,
|
||||
list: false,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -526,6 +538,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: false,
|
||||
list: true,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -544,6 +557,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
strings: true,
|
||||
list: false,
|
||||
},
|
||||
attr_style: self.attr_style,
|
||||
})
|
||||
}
|
||||
|
||||
@ -802,6 +816,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
},
|
||||
},
|
||||
attr_span: attr.span,
|
||||
attr_style: attr.style,
|
||||
template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
};
|
||||
@ -912,6 +927,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
attr_style: attr.style,
|
||||
template: &accept.template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{self as ast, AttrStyle};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
@ -579,6 +579,7 @@ pub(crate) enum AttributeParseErrorReason {
|
||||
pub(crate) struct AttributeParseError {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) attr_span: Span,
|
||||
pub(crate) attr_style: AttrStyle,
|
||||
pub(crate) template: AttributeTemplate,
|
||||
pub(crate) attribute: AttrPath,
|
||||
pub(crate) reason: AttributeParseErrorReason,
|
||||
@ -717,7 +718,8 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
||||
if let Some(link) = self.template.docs {
|
||||
diag.note(format!("for more information, visit <{link}>"));
|
||||
}
|
||||
let suggestions = self.template.suggestions(false, &name);
|
||||
let suggestions = self.template.suggestions(self.attr_style, &name);
|
||||
|
||||
diag.span_suggestions(
|
||||
self.attr_span,
|
||||
if suggestions.len() == 1 {
|
||||
|
@ -6,6 +6,7 @@ use AttributeDuplicates::*;
|
||||
use AttributeGate::*;
|
||||
use AttributeType::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::AttrStyle;
|
||||
use rustc_hir::attrs::EncodeCrossCrate;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Symbol, sym};
|
||||
@ -132,9 +133,12 @@ pub struct AttributeTemplate {
|
||||
}
|
||||
|
||||
impl AttributeTemplate {
|
||||
pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec<String> {
|
||||
pub fn suggestions(&self, style: AttrStyle, name: impl std::fmt::Display) -> Vec<String> {
|
||||
let mut suggestions = vec![];
|
||||
let inner = if inner { "!" } else { "" };
|
||||
let inner = match style {
|
||||
AttrStyle::Outer => "",
|
||||
AttrStyle::Inner => "!",
|
||||
};
|
||||
if self.word {
|
||||
suggestions.push(format!("#{inner}[{name}]"));
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// NOTE: this used to panic in debug builds (by a sanity assertion)
|
||||
// and not emit any lint on release builds. See https://github.com/rust-lang/rust/issues/142891.
|
||||
#![inline = ""]
|
||||
//~^ ERROR: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` [ill_formed_attribute_input]
|
||||
//~^ ERROR: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]` [ill_formed_attribute_input]
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
//~| ERROR attribute cannot be used on
|
||||
|
||||
|
@ -6,7 +6,7 @@ LL | #![inline = ""]
|
||||
|
|
||||
= help: `#[inline]` can only be applied to functions
|
||||
|
||||
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
|
||||
error: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]`
|
||||
--> $DIR/lint_on_root.rs:3:1
|
||||
|
|
||||
LL | #![inline = ""]
|
||||
@ -19,7 +19,7 @@ LL | #![inline = ""]
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
|
||||
error: valid forms for the attribute are `#![inline(always)]`, `#![inline(never)]`, and `#![inline]`
|
||||
--> $DIR/lint_on_root.rs:3:1
|
||||
|
|
||||
LL | #![inline = ""]
|
||||
|
@ -7,18 +7,14 @@ LL | #![repr]
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #![repr]
|
||||
LL + #[repr(<integer type>)]
|
||||
|
|
||||
LL - #![repr]
|
||||
LL + #[repr(C)]
|
||||
|
|
||||
LL - #![repr]
|
||||
LL + #[repr(Rust)]
|
||||
|
|
||||
LL - #![repr]
|
||||
LL + #[repr(align(...))]
|
||||
|
|
||||
LL | #![repr(<integer type>)]
|
||||
| ++++++++++++++++
|
||||
LL | #![repr(C)]
|
||||
| +++
|
||||
LL | #![repr(Rust)]
|
||||
| ++++++
|
||||
LL | #![repr(align(...))]
|
||||
| ++++++++++++
|
||||
= and 2 other candidates
|
||||
|
||||
error[E0589]: invalid `repr(align)` attribute: not a power of two
|
||||
|
@ -22,10 +22,10 @@ LL | #![coverage = "off"]
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #![coverage = "off"]
|
||||
LL + #[coverage(off)]
|
||||
LL + #![coverage(off)]
|
||||
|
|
||||
LL - #![coverage = "off"]
|
||||
LL + #[coverage(on)]
|
||||
LL + #![coverage(on)]
|
||||
|
|
||||
|
||||
error[E0539]: malformed `coverage` attribute input
|
||||
|
@ -19,12 +19,10 @@ LL | #![coverage]
|
||||
|
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #![coverage]
|
||||
LL + #[coverage(off)]
|
||||
|
|
||||
LL - #![coverage]
|
||||
LL + #[coverage(on)]
|
||||
|
|
||||
LL | #![coverage(off)]
|
||||
| +++++
|
||||
LL | #![coverage(on)]
|
||||
| ++++
|
||||
|
||||
error[E0539]: malformed `coverage` attribute input
|
||||
--> $DIR/word-only.rs:21:1
|
||||
|
@ -11,7 +11,7 @@ LL | #![path = foo!()]
|
||||
| ^^^^^^^^^^------^
|
||||
| | |
|
||||
| | expected a string literal here
|
||||
| help: must be of the form: `#[path = "file"]`
|
||||
| help: must be of the form: `#![path = "file"]`
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user