1
Fork 0

Add some additional warnings for duplicated diagnostic items

This commit adds warnings if a user supplies several diagnostic options
where we can only apply one of them. We explicitly warn about ignored
options here. In addition a small test for these warnings is added.
This commit is contained in:
Georg Semmler 2023-11-09 08:33:21 +01:00
parent 4770d91093
commit 10538d4d2b
No known key found for this signature in database
GPG key ID: A87BCEE5205CE489
7 changed files with 219 additions and 17 deletions

View file

@ -321,7 +321,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString(Symbol);
pub struct OnUnimplementedFormatString(Symbol, Span);
#[derive(Debug)]
pub struct OnUnimplementedDirective {
@ -350,7 +350,7 @@ pub struct OnUnimplementedNote {
pub enum AppendConstMessage {
#[default]
Default,
Custom(Symbol),
Custom(Symbol, Span),
}
#[derive(LintDiagnostic)]
@ -372,6 +372,35 @@ impl MalformedOnUnimplementedAttrLint {
#[help]
pub struct MissingOptionsForOnUnimplementedAttr;
#[derive(LintDiagnostic)]
#[diag(trait_selection_ignored_diagnostic_option)]
pub struct IgnoredDiagnosticOption {
pub option_name: &'static str,
#[label]
pub span: Span,
#[label(trait_selection_other_label)]
pub prev_span: Span,
}
impl IgnoredDiagnosticOption {
fn maybe_emit_warning<'tcx>(
tcx: TyCtxt<'tcx>,
item_def_id: DefId,
new: Option<Span>,
old: Option<Span>,
option_name: &'static str,
) {
if let (Some(new_item), Some(old_item)) = (new, old) {
tcx.emit_spanned_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
new_item,
IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
);
}
}
}
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
@ -384,8 +413,9 @@ impl<'tcx> OnUnimplementedDirective {
let mut errored = None;
let mut item_iter = items.iter();
let parse_value = |value_str| {
OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
let parse_value = |value_str, value_span| {
OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span, value_span)
.map(Some)
};
let condition = if is_root {
@ -398,7 +428,7 @@ impl<'tcx> OnUnimplementedDirective {
.ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value
&& let Err(guar) = parse_value(value)
&& let Err(guar) = parse_value(value, cfg.span)
{
errored = Some(guar);
}
@ -417,17 +447,17 @@ impl<'tcx> OnUnimplementedDirective {
for item in item_iter {
if item.has_name(sym::message) && message.is_none() {
if let Some(message_) = item.value_str() {
message = parse_value(message_)?;
message = parse_value(message_, item.span())?;
continue;
}
} else if item.has_name(sym::label) && label.is_none() {
if let Some(label_) = item.value_str() {
label = parse_value(label_)?;
label = parse_value(label_, item.span())?;
continue;
}
} else if item.has_name(sym::note) {
if let Some(note_) = item.value_str() {
if let Some(note) = parse_value(note_)? {
if let Some(note) = parse_value(note_, item.span())? {
notes.push(note);
continue;
}
@ -437,7 +467,7 @@ impl<'tcx> OnUnimplementedDirective {
&& !is_diagnostic_namespace_variant
{
if let Some(parent_label_) = item.value_str() {
parent_label = parse_value(parent_label_)?;
parent_label = parse_value(parent_label_, item.span())?;
continue;
}
} else if item.has_name(sym::on)
@ -470,7 +500,7 @@ impl<'tcx> OnUnimplementedDirective {
&& !is_diagnostic_namespace_variant
{
if let Some(msg) = item.value_str() {
append_const_msg = Some(AppendConstMessage::Custom(msg));
append_const_msg = Some(AppendConstMessage::Custom(msg, item.span()));
continue;
} else if item.is_word() {
append_const_msg = Some(AppendConstMessage::Default);
@ -519,6 +549,54 @@ impl<'tcx> OnUnimplementedDirective {
subcommands.extend(directive.subcommands);
let mut notes = aggr.notes;
notes.extend(directive.notes);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.message.as_ref().map(|f| f.1),
aggr.message.as_ref().map(|f| f.1),
"message",
);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.label.as_ref().map(|f| f.1),
aggr.label.as_ref().map(|f| f.1),
"label",
);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.condition.as_ref().map(|i| i.span),
aggr.condition.as_ref().map(|i| i.span),
"condition",
);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.parent_label.as_ref().map(|f| f.1),
aggr.parent_label.as_ref().map(|f| f.1),
"parent_label",
);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.append_const_msg.as_ref().and_then(|c| {
if let AppendConstMessage::Custom(_, s) = c {
Some(*s)
} else {
None
}
}),
aggr.append_const_msg.as_ref().and_then(|c| {
if let AppendConstMessage::Custom(_, s) = c {
Some(*s)
} else {
None
}
}),
"append_const_msg",
);
Ok(Some(Self {
condition: aggr.condition.or(directive.condition),
subcommands,
@ -556,6 +634,7 @@ impl<'tcx> OnUnimplementedDirective {
item_def_id,
value,
attr.span,
attr.span,
)?),
notes: Vec::new(),
parent_label: None,
@ -633,7 +712,11 @@ impl<'tcx> OnUnimplementedDirective {
// `with_no_visible_paths` is also used when generating the options,
// so we need to match it here.
ty::print::with_no_visible_paths!(
OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
OnUnimplementedFormatString(v, cfg.span).format(
tcx,
trait_ref,
&options_map
)
)
});
@ -678,8 +761,9 @@ impl<'tcx> OnUnimplementedFormatString {
item_def_id: DefId,
from: Symbol,
err_sp: Span,
value_span: Span,
) -> Result<Self, ErrorGuaranteed> {
let result = OnUnimplementedFormatString(from);
let result = OnUnimplementedFormatString(from, value_span);
result.verify(tcx, item_def_id, err_sp)?;
Ok(result)
}

View file

@ -2729,7 +2729,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Some(format!("{cannot_do_this} in const contexts"))
}
// overridden post message
(true, Some(AppendConstMessage::Custom(custom_msg))) => {
(true, Some(AppendConstMessage::Custom(custom_msg, _))) => {
Some(format!("{cannot_do_this}{custom_msg}"))
}
// fallback to generic message