mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-04 09:53:04 +03:00
Auto merge of #155760 - GuillaumeGomez:rm-attributelintkind, r=JonathanBrouwer,petrochenkov
Remove `AttributeLintKind` Part of https://github.com/rust-lang/rust/issues/153099. The `AttributeLintKind` type is finally gone! \o/ Diff is this big because I moved a file and a lot of `Diagnostic` types. :') r? @JonathanBrouwer
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
|
||||
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
@@ -52,7 +52,7 @@
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::PerParentDisambiguatorState;
|
||||
use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
||||
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
|
||||
@@ -1096,23 +1096,18 @@ fn lower_attrs_vec(
|
||||
target,
|
||||
OmitDoc::Lower,
|
||||
|s| l.lower(s),
|
||||
|lint_id, span, kind| match kind {
|
||||
EmitAttribute::Static(attr_kind) => {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
kind: attr_kind,
|
||||
}));
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
callback,
|
||||
}));
|
||||
}
|
||||
|lint_id, span, kind| {
|
||||
self.delayed_lints.push(DelayedLint {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
callback: Box::new(move |dcx, level, sess: &dyn std::any::Any| {
|
||||
let sess = sess
|
||||
.downcast_ref::<rustc_session::Session>()
|
||||
.expect("expected `Session`");
|
||||
(kind.0)(dcx, level, sess)
|
||||
}),
|
||||
});
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::DelimSpan;
|
||||
use rustc_ast::{AttrItem, Attribute, LitKind, ast, token};
|
||||
use rustc_errors::{Applicability, PResult, msg};
|
||||
use rustc_errors::{Applicability, Diagnostic, PResult, msg};
|
||||
use rustc_feature::{
|
||||
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
||||
};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrPath, RustcVersion, Target};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||
use rustc_parse::{exp, parse_in};
|
||||
@@ -20,6 +19,7 @@
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::attributes::diagnostic::check_cfg;
|
||||
use crate::context::{AcceptContext, ShouldEmit, Stage};
|
||||
use crate::parser::{
|
||||
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
|
||||
@@ -224,14 +224,19 @@ pub(crate) fn parse_name_value<S: Stage>(
|
||||
|
||||
match cx.sess.psess.check_config.expecteds.get(&name) {
|
||||
Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx
|
||||
.emit_lint(
|
||||
.emit_dyn_lint_with_sess(
|
||||
UNEXPECTED_CFGS,
|
||||
AttributeLintKind::UnexpectedCfgValue((name, name_span), value),
|
||||
move |dcx, level, sess| {
|
||||
check_cfg::unexpected_cfg_value(sess, (name, name_span), value)
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
),
|
||||
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint(
|
||||
None if cx.sess.psess.check_config.exhaustive_names => cx.emit_dyn_lint_with_sess(
|
||||
UNEXPECTED_CFGS,
|
||||
AttributeLintKind::UnexpectedCfgName((name, name_span), value),
|
||||
move |dcx, level, sess| {
|
||||
check_cfg::unexpected_cfg_name(sess, (name, name_span), value).into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
),
|
||||
_ => { /* not unexpected */ }
|
||||
|
||||
+51
-63
@@ -1,12 +1,10 @@
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{ExpnKind, Ident, Span, Symbol, sym};
|
||||
|
||||
use crate::lints;
|
||||
use crate::errors;
|
||||
|
||||
const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
|
||||
|
||||
@@ -64,57 +62,48 @@ fn to_check_cfg_arg(name: Ident, value: Option<Symbol>, quotes: EscapeQuotes) ->
|
||||
fn cargo_help_sub(
|
||||
sess: &Session,
|
||||
inst: &impl Fn(EscapeQuotes) -> String,
|
||||
) -> lints::UnexpectedCfgCargoHelp {
|
||||
) -> errors::UnexpectedCfgCargoHelp {
|
||||
// We don't want to suggest the `build.rs` way to expected cfgs if we are already in a
|
||||
// `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is
|
||||
// `build_script_build`) to try to figure out if we are building a Cargo build script
|
||||
|
||||
let unescaped = &inst(EscapeQuotes::No);
|
||||
if let Some("build_script_build") = sess.opts.crate_name.as_deref() {
|
||||
lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
|
||||
errors::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
|
||||
} else {
|
||||
lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
|
||||
errors::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_macro_help(span: Span) -> Option<lints::UnexpectedCfgRustcMacroHelp> {
|
||||
fn rustc_macro_help(span: Span) -> Option<errors::UnexpectedCfgRustcMacroHelp> {
|
||||
let oexpn = span.ctxt().outer_expn_data();
|
||||
if let Some(def_id) = oexpn.macro_def_id
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
&& def_id.krate != LOCAL_CRATE
|
||||
{
|
||||
Some(lints::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
|
||||
Some(errors::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn cargo_macro_help(
|
||||
tcx: Option<TyCtxt<'_>>,
|
||||
span: Span,
|
||||
) -> Option<lints::UnexpectedCfgCargoMacroHelp> {
|
||||
fn cargo_macro_help(span: Span) -> Option<errors::UnexpectedCfgCargoMacroHelp> {
|
||||
let oexpn = span.ctxt().outer_expn_data();
|
||||
if let Some(def_id) = oexpn.macro_def_id
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
&& def_id.krate != LOCAL_CRATE
|
||||
&& let Some(tcx) = tcx
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
{
|
||||
Some(lints::UnexpectedCfgCargoMacroHelp {
|
||||
macro_kind: macro_kind.descr(),
|
||||
macro_name,
|
||||
crate_name: tcx.crate_name(def_id.krate),
|
||||
})
|
||||
Some(errors::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn unexpected_cfg_name(
|
||||
pub(crate) fn unexpected_cfg_name(
|
||||
sess: &Session,
|
||||
tcx: Option<TyCtxt<'_>>,
|
||||
(name, name_span): (Symbol, Span),
|
||||
value: Option<(Symbol, Span)>,
|
||||
) -> lints::UnexpectedCfgName {
|
||||
) -> errors::UnexpectedCfgName {
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
|
||||
|
||||
@@ -149,12 +138,12 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
}
|
||||
|
||||
let code_sugg = if is_feature_cfg && is_from_cargo {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
|
||||
errors::unexpected_cfg_name::CodeSuggestion::DefineFeatures
|
||||
// Suggest correct `version("..")` predicate syntax
|
||||
} else if let Some((_value, value_span)) = value
|
||||
&& name == sym::version
|
||||
{
|
||||
lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
|
||||
between_name_and_value: name_span.between(value_span),
|
||||
after_value: value_span.shrink_to_hi(),
|
||||
}
|
||||
@@ -169,7 +158,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
.span_to_snippet(name_span)
|
||||
.map_or(true, |snippet| !snippet.contains("r#"))
|
||||
{
|
||||
lints::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
|
||||
span: name_span,
|
||||
literal: boolean,
|
||||
}
|
||||
@@ -189,7 +178,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
if !possibilities.is_empty() {
|
||||
let possibilities =
|
||||
possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
|
||||
Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
|
||||
Some(errors::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -198,37 +187,37 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
let best_match = Ident::new(best_match, name_span);
|
||||
if let Some((value, value_span)) = value {
|
||||
if best_match_values.contains(&Some(value)) {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
}
|
||||
} else if best_match_values.contains(&None) {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
|
||||
span: name_span.to(value_span),
|
||||
code: best_match.to_string(),
|
||||
}
|
||||
} else if let Some(first_value) = possibilities.first() {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
span: name_span.to(value_span),
|
||||
code: format!("{best_match} = \"{first_value}\""),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
} else {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
span: name_span.to(value_span),
|
||||
code: best_match.to_string(),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
expected: None,
|
||||
@@ -239,7 +228,7 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
names_possibilities.sort();
|
||||
names_possibilities
|
||||
.iter()
|
||||
.map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue {
|
||||
.map(|cfg_name| errors::unexpected_cfg_name::FoundWithSimilarValue {
|
||||
span: name_span,
|
||||
code: format!("{cfg_name} = \"{name}\""),
|
||||
})
|
||||
@@ -253,14 +242,14 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
let expected_names = if !possibilities.is_empty() {
|
||||
let possibilities: Vec<_> =
|
||||
possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
|
||||
Some(lints::unexpected_cfg_name::ExpectedNames {
|
||||
Some(errors::unexpected_cfg_name::ExpectedNames {
|
||||
possibilities: possibilities.into(),
|
||||
and_more,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarValues {
|
||||
errors::unexpected_cfg_name::CodeSuggestion::SimilarValues {
|
||||
with_similar_values: similar_values,
|
||||
expected_names,
|
||||
}
|
||||
@@ -276,29 +265,28 @@ fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_name::InvocationHelp::Cargo {
|
||||
errors::unexpected_cfg_name::InvocationHelp::Cargo {
|
||||
help,
|
||||
macro_help: cargo_macro_help(tcx, name_span),
|
||||
macro_help: cargo_macro_help(name_span),
|
||||
}
|
||||
} else {
|
||||
let help = lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
|
||||
lints::unexpected_cfg_name::InvocationHelp::Rustc {
|
||||
let help = errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
|
||||
errors::unexpected_cfg_name::InvocationHelp::Rustc {
|
||||
help,
|
||||
macro_help: rustc_macro_help(name_span),
|
||||
}
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgName { code_sugg, invocation_help, name }
|
||||
errors::UnexpectedCfgName { code_sugg, invocation_help, name }
|
||||
}
|
||||
|
||||
pub(super) fn unexpected_cfg_value(
|
||||
pub(crate) fn unexpected_cfg_value(
|
||||
sess: &Session,
|
||||
tcx: Option<TyCtxt<'_>>,
|
||||
(name, name_span): (Symbol, Span),
|
||||
value: Option<(Symbol, Span)>,
|
||||
) -> lints::UnexpectedCfgValue {
|
||||
) -> errors::UnexpectedCfgValue {
|
||||
let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
|
||||
bug!(
|
||||
panic!(
|
||||
"it shouldn't be possible to have a diagnostic on a value whose name is not in values"
|
||||
);
|
||||
};
|
||||
@@ -327,13 +315,13 @@ pub(super) fn unexpected_cfg_value(
|
||||
.iter()
|
||||
.take(max_suggestions)
|
||||
.copied()
|
||||
.map(|name| lints::unexpected_cfg_value::ChangeNameSuggestion {
|
||||
.map(|name| errors::unexpected_cfg_value::ChangeNameSuggestion {
|
||||
span: name_span,
|
||||
name,
|
||||
value,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
lints::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
|
||||
errors::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
|
||||
} else if !possibilities.is_empty() {
|
||||
// Show the full list if all possible values for a given name, but don't do it
|
||||
// for names as the possibilities could be very long
|
||||
@@ -343,7 +331,7 @@ pub(super) fn unexpected_cfg_value(
|
||||
possibilities.clone(),
|
||||
FilterWellKnownNames::No,
|
||||
);
|
||||
lints::unexpected_cfg_value::ExpectedValues {
|
||||
errors::unexpected_cfg_value::ExpectedValues {
|
||||
name,
|
||||
have_none_possibility,
|
||||
possibilities: possibilities.into(),
|
||||
@@ -354,7 +342,7 @@ pub(super) fn unexpected_cfg_value(
|
||||
let suggestion = if let Some((value, value_span)) = value {
|
||||
// Suggest the most probable if we found one
|
||||
if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
|
||||
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
|
||||
Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
|
||||
span: value_span,
|
||||
best_match,
|
||||
})
|
||||
@@ -362,7 +350,7 @@ pub(super) fn unexpected_cfg_value(
|
||||
None
|
||||
}
|
||||
} else if let &[first_possibility] = &possibilities[..] {
|
||||
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
|
||||
Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
|
||||
span: name_span.shrink_to_hi(),
|
||||
first_possibility,
|
||||
})
|
||||
@@ -370,21 +358,21 @@ pub(super) fn unexpected_cfg_value(
|
||||
None
|
||||
};
|
||||
|
||||
lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
|
||||
errors::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
|
||||
} else if have_none_possibility {
|
||||
let suggestion =
|
||||
value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion {
|
||||
value.map(|(_value, value_span)| errors::unexpected_cfg_value::RemoveValueSuggestion {
|
||||
span: name_span.shrink_to_hi().to(value_span),
|
||||
});
|
||||
lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
|
||||
errors::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
|
||||
} else {
|
||||
let span = if let Some((_value, value_span)) = value {
|
||||
name_span.to(value_span)
|
||||
} else {
|
||||
name_span
|
||||
};
|
||||
let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span };
|
||||
lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
|
||||
let suggestion = errors::unexpected_cfg_value::RemoveConditionSuggestion { span };
|
||||
errors::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
|
||||
};
|
||||
|
||||
// We don't want to encourage people to add values to a well-known names, as these are
|
||||
@@ -405,32 +393,32 @@ pub(super) fn unexpected_cfg_value(
|
||||
let invocation_help = if is_from_cargo {
|
||||
let help = if name == sym::feature && !is_from_external_macro {
|
||||
if let Some((value, _value_span)) = value {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
|
||||
Some(errors::unexpected_cfg_value::CargoHelp::AddFeature { value })
|
||||
} else {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
Some(errors::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
}
|
||||
} else if can_suggest_adding_value && !is_from_external_macro {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
|
||||
Some(errors::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo {
|
||||
errors::unexpected_cfg_value::InvocationHelp::Cargo {
|
||||
help,
|
||||
macro_help: cargo_macro_help(tcx, name_span),
|
||||
macro_help: cargo_macro_help(name_span),
|
||||
}
|
||||
} else {
|
||||
let help = if can_suggest_adding_value {
|
||||
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
Some(errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Rustc {
|
||||
errors::unexpected_cfg_value::InvocationHelp::Rustc {
|
||||
help,
|
||||
macro_help: rustc_macro_help(name_span),
|
||||
}
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgValue {
|
||||
errors::UnexpectedCfgValue {
|
||||
code_sugg,
|
||||
invocation_help,
|
||||
has_value: value.is_some(),
|
||||
@@ -23,6 +23,7 @@
|
||||
};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
|
||||
|
||||
pub(crate) mod check_cfg;
|
||||
pub(crate) mod do_not_recommend;
|
||||
pub(crate) mod on_const;
|
||||
pub(crate) mod on_move;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
|
||||
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrPath, HirId};
|
||||
use rustc_parse::parser::Recovery;
|
||||
use rustc_session::Session;
|
||||
@@ -460,18 +459,6 @@ pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuarant
|
||||
self.stage.emit_err(&self.sess, diag)
|
||||
}
|
||||
|
||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_lint(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
kind: AttributeLintKind,
|
||||
span: impl Into<MultiSpan>,
|
||||
) {
|
||||
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
|
||||
}
|
||||
|
||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
@@ -483,7 +470,25 @@ pub(crate) fn emit_dyn_lint<
|
||||
callback: F,
|
||||
span: impl Into<MultiSpan>,
|
||||
) {
|
||||
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
|
||||
self.emit_lint_inner(
|
||||
lint,
|
||||
EmitAttribute(Box::new(move |dcx, level, _| callback(dcx, level))),
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn emit_dyn_lint_with_sess<
|
||||
F: for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
|
||||
+ DynSend
|
||||
+ DynSync
|
||||
+ 'static,
|
||||
>(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
callback: F,
|
||||
span: impl Into<MultiSpan>,
|
||||
) {
|
||||
self.emit_lint_inner(lint, EmitAttribute(Box::new(callback)), span);
|
||||
}
|
||||
|
||||
fn emit_lint_inner(
|
||||
|
||||
@@ -421,3 +421,371 @@ pub(crate) enum FormatWarning {
|
||||
allowed: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum UnexpectedCfgCargoHelp {
|
||||
#[help("consider using a Cargo feature instead")]
|
||||
#[help(
|
||||
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
|
||||
)]
|
||||
LintCfg { cargo_toml_lint_cfg: String },
|
||||
#[help("consider using a Cargo feature instead")]
|
||||
#[help(
|
||||
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
|
||||
)]
|
||||
#[help("or consider adding `{$build_rs_println}` to the top of the `build.rs`")]
|
||||
LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
|
||||
}
|
||||
|
||||
impl UnexpectedCfgCargoHelp {
|
||||
fn cargo_toml_lint_cfg(unescaped: &str) -> String {
|
||||
format!(
|
||||
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn lint_cfg(unescaped: &str) -> Self {
|
||||
UnexpectedCfgCargoHelp::LintCfg {
|
||||
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
|
||||
UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
|
||||
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
|
||||
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help("to expect this configuration use `{$cmdline_arg}`")]
|
||||
pub(crate) struct UnexpectedCfgRustcHelp {
|
||||
pub cmdline_arg: String,
|
||||
}
|
||||
|
||||
impl UnexpectedCfgRustcHelp {
|
||||
pub(crate) fn new(unescaped: &str) -> Self {
|
||||
Self { cmdline_arg: format!("--check-cfg={unescaped}") }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
|
||||
)]
|
||||
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
|
||||
pub(crate) struct UnexpectedCfgRustcMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
|
||||
)]
|
||||
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
|
||||
pub(crate) struct UnexpectedCfgCargoMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unexpected `cfg` condition name: `{$name}`")]
|
||||
pub(crate) struct UnexpectedCfgName {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_name::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_name::InvocationHelp,
|
||||
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
pub(crate) mod unexpected_cfg_name {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CodeSuggestion {
|
||||
#[help("consider defining some features in `Cargo.toml`")]
|
||||
DefineFeatures,
|
||||
#[multipart_suggestion(
|
||||
"there is a similar config predicate: `version(\"..\")`",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
VersionSyntax {
|
||||
#[suggestion_part(code = "(")]
|
||||
between_name_and_value: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
after_value: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameAndValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and no value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameNoValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and different values",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameDifferentValues {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
SimilarValues {
|
||||
#[subdiagnostic]
|
||||
with_similar_values: Vec<FoundWithSimilarValue>,
|
||||
#[subdiagnostic]
|
||||
expected_names: Option<ExpectedNames>,
|
||||
},
|
||||
#[suggestion(
|
||||
"you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose",
|
||||
code = "{literal}"
|
||||
)]
|
||||
BooleanLiteral {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
literal: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help("expected values for `{$best_match}` are: {$possibilities}")]
|
||||
pub(crate) struct ExpectedValues {
|
||||
pub best_match: Symbol,
|
||||
pub possibilities: DiagSymbolList,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"found config with similar value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
pub(crate) struct FoundWithSimilarValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help_once(
|
||||
"expected names are: {$possibilities}{$and_more ->
|
||||
[0] {\"\"}
|
||||
*[other] {\" \"}and {$and_more} more
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct ExpectedNames {
|
||||
pub possibilities: DiagSymbolList<Ident>,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvocationHelp {
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgCargoHelp>,
|
||||
},
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: super::UnexpectedCfgRustcHelp,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"unexpected `cfg` condition value: {$has_value ->
|
||||
[true] `{$value}`
|
||||
*[false] (none)
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct UnexpectedCfgValue {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_value::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_value::InvocationHelp,
|
||||
|
||||
pub has_value: bool,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
pub(crate) mod unexpected_cfg_value {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CodeSuggestion {
|
||||
ChangeValue {
|
||||
#[subdiagnostic]
|
||||
expected_values: ExpectedValues,
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<ChangeValueSuggestion>,
|
||||
},
|
||||
#[note("no expected value for `{$name}`")]
|
||||
RemoveValue {
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<RemoveValueSuggestion>,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
#[note("no expected values for `{$name}`")]
|
||||
RemoveCondition {
|
||||
#[subdiagnostic]
|
||||
suggestion: RemoveConditionSuggestion,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
ChangeName {
|
||||
#[subdiagnostic]
|
||||
suggestions: Vec<ChangeNameSuggestion>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ChangeValueSuggestion {
|
||||
#[suggestion(
|
||||
"there is a expected value with a similar name",
|
||||
code = r#""{best_match}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
best_match: Symbol,
|
||||
},
|
||||
#[suggestion(
|
||||
"specify a config value",
|
||||
code = r#" = "{first_possibility}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SpecifyValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
first_possibility: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("remove the value", code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) struct RemoveValueSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("remove the condition", code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) struct RemoveConditionSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"expected values for `{$name}` are: {$have_none_possibility ->
|
||||
[true] {\"(none), \"}
|
||||
*[false] {\"\"}
|
||||
}{$possibilities}{$and_more ->
|
||||
[0] {\"\"}
|
||||
*[other] {\" \"}and {$and_more} more
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct ExpectedValues {
|
||||
pub name: Symbol,
|
||||
pub have_none_possibility: bool,
|
||||
pub possibilities: DiagSymbolList,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"`{$value}` is an expected value for `{$name}`",
|
||||
code = "{name}",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub(crate) struct ChangeNameSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
pub value: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvocationHelp {
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
help: Option<CargoHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
},
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgRustcHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CargoHelp {
|
||||
#[help("consider adding `{$value}` as a feature in `Cargo.toml`")]
|
||||
AddFeature {
|
||||
value: Symbol,
|
||||
},
|
||||
#[help("consider defining some features in `Cargo.toml`")]
|
||||
DefineFeatures,
|
||||
Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::LintId;
|
||||
@@ -20,14 +19,14 @@
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
||||
pub enum EmitAttribute {
|
||||
Static(AttributeLintKind),
|
||||
Dynamic(
|
||||
Box<
|
||||
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
|
||||
>,
|
||||
),
|
||||
}
|
||||
pub struct EmitAttribute(
|
||||
pub Box<
|
||||
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
|
||||
+ DynSend
|
||||
+ DynSync
|
||||
+ 'static,
|
||||
>,
|
||||
);
|
||||
|
||||
/// Context created once, for example as part of the ast lowering
|
||||
/// context, through which all attributes can be lowered.
|
||||
@@ -127,13 +126,8 @@ pub fn parse_limited_all(
|
||||
target,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|lint_id, span, kind| match kind {
|
||||
EmitAttribute::Static(kind) => {
|
||||
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
|
||||
}
|
||||
|lint_id, span, kind| {
|
||||
sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -214,13 +208,8 @@ pub fn parse_single_args<T, I>(
|
||||
sess,
|
||||
stage: Early { emit_errors },
|
||||
};
|
||||
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| match kind {
|
||||
EmitAttribute::Static(kind) => {
|
||||
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
|
||||
}
|
||||
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| {
|
||||
sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0)
|
||||
};
|
||||
if let Some(safety) = attr_safety {
|
||||
parser.check_attribute_safety(
|
||||
|
||||
@@ -79,7 +79,7 @@ pub fn check_attribute_safety(
|
||||
emit_lint(
|
||||
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
|
||||
path_span.into(),
|
||||
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
|
||||
EmitAttribute(Box::new(move |dcx, level, _| {
|
||||
errors::UnsafeAttrOutsideUnsafeLint {
|
||||
span: path_span,
|
||||
suggestion: not_from_proc_macro
|
||||
|
||||
@@ -635,7 +635,7 @@ enum ArgRef<'a> {
|
||||
span: Some(arg_name.span.into()),
|
||||
node_id: rustc_ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: DecorateDiagCompat::Dynamic(Box::new(move |dcx, level, sess| {
|
||||
diagnostic: DecorateDiagCompat(Box::new(move |dcx, level, sess| {
|
||||
let (suggestion, name) =
|
||||
if let Some(positional_arg_to_replace) = position_sp_to_replace {
|
||||
let mut name = arg_name.name.to_string();
|
||||
|
||||
@@ -5,25 +5,20 @@
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_lint_defs::{AttributeLintKind, Lint, LintId};
|
||||
use rustc_lint_defs::{Lint, LintId};
|
||||
|
||||
use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};
|
||||
|
||||
/// We can't implement `Diagnostic` for `AttributeLintKind`, because decorating some of its
|
||||
/// variants requires types we don't have yet. So, handle that case separately.
|
||||
pub enum DecorateDiagCompat {
|
||||
pub struct DecorateDiagCompat(
|
||||
/// The third argument of the closure is a `Session`. However, due to the dependency tree,
|
||||
/// we don't have access to `rustc_session` here, so we downcast it when needed.
|
||||
Dynamic(
|
||||
Box<
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSync
|
||||
+ DynSend
|
||||
+ 'static,
|
||||
>,
|
||||
),
|
||||
Builtin(AttributeLintKind),
|
||||
}
|
||||
pub Box<
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSync
|
||||
+ DynSend
|
||||
+ 'static,
|
||||
>,
|
||||
);
|
||||
|
||||
impl std::fmt::Debug for DecorateDiagCompat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -34,14 +29,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(d: D) -> Self {
|
||||
Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AttributeLintKind> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(b: AttributeLintKind) -> Self {
|
||||
Self::Builtin(b)
|
||||
Self(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +94,7 @@ pub fn dyn_buffer_lint<
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
diagnostic: DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,7 +114,7 @@ pub fn dyn_buffer_lint_any<
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic: DecorateDiagCompat::Dynamic(Box::new(callback)),
|
||||
diagnostic: DecorateDiagCompat(Box::new(callback)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,18 +129,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiagCallback<'a>(
|
||||
pub &'a Box<
|
||||
dyn for<'b> Fn(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + DynSync + 'static,
|
||||
>,
|
||||
);
|
||||
|
||||
impl<'a, 'b> Diagnostic<'a, ()> for DiagCallback<'b> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
(self.0)(dcx, level)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
|
||||
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
pub use codes::*;
|
||||
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
pub use diagnostic::{
|
||||
BugAbort, Diag, DiagCallback, DiagDecorator, DiagInner, DiagLocation, DiagStyledString,
|
||||
Diagnostic, EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
|
||||
BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic,
|
||||
EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
|
||||
};
|
||||
pub use diagnostic_impls::{
|
||||
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Level};
|
||||
pub use rustc_lint_defs::AttributeLintKind;
|
||||
use rustc_lint_defs::LintId;
|
||||
|
||||
use crate::HirId;
|
||||
@@ -14,32 +13,21 @@
|
||||
/// and then there's a gap where no lints can be emitted until HIR is done.
|
||||
/// The variants in this enum represent lints that are temporarily stashed during
|
||||
/// AST lowering to be emitted once HIR is built.
|
||||
#[derive(Debug)]
|
||||
pub enum DelayedLint {
|
||||
AttributeParsing(AttributeLint),
|
||||
Dynamic(DynAttribute),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AttributeLint {
|
||||
pub lint_id: LintId,
|
||||
pub id: HirId,
|
||||
pub span: MultiSpan,
|
||||
pub kind: AttributeLintKind,
|
||||
}
|
||||
|
||||
pub struct DynAttribute {
|
||||
pub struct DelayedLint {
|
||||
pub lint_id: LintId,
|
||||
pub id: HirId,
|
||||
pub span: MultiSpan,
|
||||
pub callback: Box<
|
||||
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
|
||||
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &dyn std::any::Any) -> Diag<'a, ()>
|
||||
+ DynSend
|
||||
+ DynSync
|
||||
+ 'static,
|
||||
>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for DynAttribute {
|
||||
impl std::fmt::Debug for DelayedLint {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DynAttribute")
|
||||
f.debug_struct("DelayedLint")
|
||||
.field("lint_id", &self.lint_id)
|
||||
.field("id", &self.id)
|
||||
.field("span", &self.span)
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
use rustc_codegen_ssa::{CompiledModules, CrateInfo};
|
||||
use rustc_data_structures::indexmap::IndexMap;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal, par_fns};
|
||||
use rustc_data_structures::sync::{
|
||||
AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, par_fns,
|
||||
};
|
||||
use rustc_data_structures::thousands;
|
||||
use rustc_errors::DiagCallback;
|
||||
use rustc_errors::timings::TimingSection;
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
|
||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_feature::Features;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
@@ -22,12 +24,9 @@
|
||||
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{Attribute, MaybeOwner, Target, find_attr};
|
||||
use rustc_incremental::setup_dep_graph;
|
||||
use rustc_lint::{
|
||||
BufferedEarlyLint, DecorateAttrLint, EarlyCheckNode, LintStore, unerased_lint_store,
|
||||
};
|
||||
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
@@ -97,7 +96,6 @@ fn pre_expansion_lint<'a>(
|
||||
|| {
|
||||
rustc_lint::check_ast_node(
|
||||
sess,
|
||||
None,
|
||||
features,
|
||||
true,
|
||||
lint_store,
|
||||
@@ -141,7 +139,7 @@ fn configure_and_expand(
|
||||
let tcx = resolver.tcx();
|
||||
let sess = tcx.sess;
|
||||
let features = tcx.features();
|
||||
let lint_store = unerased_lint_store(tcx.sess);
|
||||
let lint_store = unerased_lint_store(sess);
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
let lint_check_node = (&krate, pre_configured_attrs);
|
||||
pre_expansion_lint(
|
||||
@@ -470,7 +468,6 @@ const fn as_str(self) -> &'static str {
|
||||
let lint_store = unerased_lint_store(tcx.sess);
|
||||
rustc_lint::check_ast_node(
|
||||
sess,
|
||||
Some(tcx),
|
||||
tcx.features(),
|
||||
false,
|
||||
lint_store,
|
||||
@@ -1028,30 +1025,29 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
||||
)
|
||||
}
|
||||
|
||||
struct DiagCallback<'a, 'tcx> {
|
||||
callback: &'a Box<
|
||||
dyn for<'b> Fn(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + DynSync,
|
||||
>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for DiagCallback<'b, 'tcx> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
(self.callback)(dcx, level, self.tcx.sess)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
|
||||
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
|
||||
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
|
||||
for lint in delayed_lints {
|
||||
match lint {
|
||||
DelayedLint::AttributeParsing(attribute_lint) => {
|
||||
tcx.emit_node_span_lint(
|
||||
attribute_lint.lint_id.lint,
|
||||
attribute_lint.id,
|
||||
attribute_lint.span.clone(),
|
||||
DecorateAttrLint {
|
||||
sess: tcx.sess,
|
||||
tcx: Some(tcx),
|
||||
diagnostic: &attribute_lint.kind,
|
||||
},
|
||||
);
|
||||
}
|
||||
DelayedLint::Dynamic(attribute_lint) => tcx.emit_node_span_lint(
|
||||
attribute_lint.lint_id.lint,
|
||||
attribute_lint.id,
|
||||
attribute_lint.span.clone(),
|
||||
DiagCallback(&attribute_lint.callback),
|
||||
),
|
||||
}
|
||||
tcx.emit_node_span_lint(
|
||||
lint.lint_id.lint,
|
||||
lint.id,
|
||||
lint.span.clone(),
|
||||
DiagCallback { callback: &lint.callback, tcx },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
|
||||
use rustc_ast::{self as ast, AttrVec, HasAttrs};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
use rustc_errors::{BufferedEarlyLint, LintBuffer};
|
||||
use rustc_feature::Features;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
use rustc_middle::ty::RegisteredTools;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::LintPass;
|
||||
use rustc_span::{Ident, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::DiagAndSess;
|
||||
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||
use crate::{DecorateAttrLint, DiagAndSess};
|
||||
|
||||
pub(super) mod diagnostics;
|
||||
|
||||
@@ -27,36 +27,20 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
||||
|
||||
/// Implements the AST traversal for early lint passes. `T` provides the
|
||||
/// `check_*` methods.
|
||||
pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> {
|
||||
pub struct EarlyContextAndPass<'ecx, T: EarlyLintPass> {
|
||||
context: EarlyContext<'ecx>,
|
||||
tcx: Option<TyCtxt<'tcx>>,
|
||||
pass: T,
|
||||
}
|
||||
|
||||
impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
|
||||
impl<'ecx, T: EarlyLintPass> EarlyContextAndPass<'ecx, T> {
|
||||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
match diagnostic {
|
||||
DecorateDiagCompat::Builtin(b) => {
|
||||
self.context.opt_span_lint(
|
||||
lint_id.lint,
|
||||
span,
|
||||
DecorateAttrLint {
|
||||
sess: self.context.sess(),
|
||||
tcx: self.tcx,
|
||||
diagnostic: &b,
|
||||
},
|
||||
);
|
||||
}
|
||||
DecorateDiagCompat::Dynamic(callback) => {
|
||||
self.context.opt_span_lint(
|
||||
lint_id.lint,
|
||||
span,
|
||||
DiagAndSess { callback, sess: self.context.sess() },
|
||||
);
|
||||
}
|
||||
}
|
||||
self.context.opt_span_lint(
|
||||
lint_id.lint,
|
||||
span,
|
||||
DiagAndSess { callback: diagnostic.0, sess: self.context.sess() },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,9 +64,7 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'_ [ast::Attribute], f
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
|
||||
for EarlyContextAndPass<'ecx, 'tcx, T>
|
||||
{
|
||||
impl<'ast, 'ecx, T: EarlyLintPass> ast_visit::Visitor<'ast> for EarlyContextAndPass<'ecx, T> {
|
||||
fn visit_id(&mut self, id: rustc_ast::NodeId) {
|
||||
self.check_id(id);
|
||||
}
|
||||
@@ -297,7 +279,7 @@ impl EarlyLintPass for RuntimeCombinedEarlyLintPass<'_> {
|
||||
pub trait EarlyCheckNode<'a>: Copy {
|
||||
fn id(self) -> ast::NodeId;
|
||||
fn attrs(self) -> &'a [ast::Attribute];
|
||||
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>);
|
||||
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>);
|
||||
}
|
||||
|
||||
impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
|
||||
@@ -307,7 +289,7 @@ fn id(self) -> ast::NodeId {
|
||||
fn attrs(self) -> &'a [ast::Attribute] {
|
||||
self.1
|
||||
}
|
||||
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
|
||||
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>) {
|
||||
lint_callback!(cx, check_crate, self.0);
|
||||
ast_visit::walk_crate(cx, self.0);
|
||||
lint_callback!(cx, check_crate_post, self.0);
|
||||
@@ -321,7 +303,7 @@ fn id(self) -> ast::NodeId {
|
||||
fn attrs(self) -> &'a [ast::Attribute] {
|
||||
self.1
|
||||
}
|
||||
fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, 'tcx, T>) {
|
||||
fn check<'ecx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx, T>) {
|
||||
walk_list!(cx, visit_attribute, self.1);
|
||||
walk_list!(cx, visit_item, self.2);
|
||||
}
|
||||
@@ -329,7 +311,6 @@ fn check<'ecx, 'tcx, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'ecx,
|
||||
|
||||
pub fn check_ast_node<'a>(
|
||||
sess: &Session,
|
||||
tcx: Option<TyCtxt<'_>>,
|
||||
features: &Features,
|
||||
pre_expansion: bool,
|
||||
lint_store: &LintStore,
|
||||
@@ -353,23 +334,22 @@ pub fn check_ast_node<'a>(
|
||||
let passes =
|
||||
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
|
||||
if passes.is_empty() {
|
||||
check_ast_node_inner(sess, tcx, check_node, context, builtin_lints);
|
||||
check_ast_node_inner(sess, check_node, context, builtin_lints);
|
||||
} else {
|
||||
let mut passes: Vec<_> = passes.iter().map(|mk_pass| (mk_pass)()).collect();
|
||||
passes.push(Box::new(builtin_lints));
|
||||
let pass = RuntimeCombinedEarlyLintPass { passes: &mut passes[..] };
|
||||
check_ast_node_inner(sess, tcx, check_node, context, pass);
|
||||
check_ast_node_inner(sess, check_node, context, pass);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ast_node_inner<'a, T: EarlyLintPass>(
|
||||
sess: &Session,
|
||||
tcx: Option<TyCtxt<'_>>,
|
||||
check_node: impl EarlyCheckNode<'a>,
|
||||
context: EarlyContext<'_>,
|
||||
pass: T,
|
||||
) {
|
||||
let mut cx = EarlyContextAndPass { context, tcx, pass };
|
||||
let mut cx = EarlyContextAndPass { context, pass };
|
||||
|
||||
cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
|
||||
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
use rustc_data_structures::sync::DynSend;
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
||||
mod check_cfg;
|
||||
|
||||
pub struct DiagAndSess<'sess> {
|
||||
pub callback: Box<
|
||||
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static,
|
||||
@@ -20,26 +16,3 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
(self.callback)(dcx, level, self.sess)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a diagnostic struct that will decorate a `AttributeLintKind`
|
||||
/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
|
||||
pub struct DecorateAttrLint<'a, 'sess, 'tcx> {
|
||||
pub sess: &'sess Session,
|
||||
pub tcx: Option<TyCtxt<'tcx>>,
|
||||
pub diagnostic: &'a AttributeLintKind,
|
||||
}
|
||||
|
||||
impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
match self.diagnostic {
|
||||
&AttributeLintKind::UnexpectedCfgName(name, value) => {
|
||||
check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value)
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
&AttributeLintKind::UnexpectedCfgValue(name, value) => {
|
||||
check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value)
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
#[rustfmt::skip]
|
||||
pub use builtin::{MissingDoc, SoftLints};
|
||||
pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
|
||||
pub use early::diagnostics::{DecorateAttrLint, DiagAndSess};
|
||||
pub use early::diagnostics::DiagAndSess;
|
||||
pub use early::{EarlyCheckNode, check_ast_node};
|
||||
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
|
||||
pub use levels::LintLevelsBuilder;
|
||||
|
||||
@@ -2653,378 +2653,6 @@ pub(crate) enum InvalidAsmLabel {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum UnexpectedCfgCargoHelp {
|
||||
#[help("consider using a Cargo feature instead")]
|
||||
#[help(
|
||||
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
|
||||
)]
|
||||
LintCfg { cargo_toml_lint_cfg: String },
|
||||
#[help("consider using a Cargo feature instead")]
|
||||
#[help(
|
||||
"or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}"
|
||||
)]
|
||||
#[help("or consider adding `{$build_rs_println}` to the top of the `build.rs`")]
|
||||
LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String },
|
||||
}
|
||||
|
||||
impl UnexpectedCfgCargoHelp {
|
||||
fn cargo_toml_lint_cfg(unescaped: &str) -> String {
|
||||
format!(
|
||||
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}"
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn lint_cfg(unescaped: &str) -> Self {
|
||||
UnexpectedCfgCargoHelp::LintCfg {
|
||||
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self {
|
||||
UnexpectedCfgCargoHelp::LintCfgAndBuildRs {
|
||||
cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped),
|
||||
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help("to expect this configuration use `{$cmdline_arg}`")]
|
||||
pub(crate) struct UnexpectedCfgRustcHelp {
|
||||
pub cmdline_arg: String,
|
||||
}
|
||||
|
||||
impl UnexpectedCfgRustcHelp {
|
||||
pub(crate) fn new(unescaped: &str) -> Self {
|
||||
Self { cmdline_arg: format!("--check-cfg={unescaped}") }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
|
||||
)]
|
||||
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
|
||||
pub(crate) struct UnexpectedCfgRustcMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate"
|
||||
)]
|
||||
#[help("try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg")]
|
||||
#[help(
|
||||
"the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}`"
|
||||
)]
|
||||
pub(crate) struct UnexpectedCfgCargoMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
pub crate_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unexpected `cfg` condition name: `{$name}`")]
|
||||
pub(crate) struct UnexpectedCfgName {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_name::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_name::InvocationHelp,
|
||||
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
pub(crate) mod unexpected_cfg_name {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CodeSuggestion {
|
||||
#[help("consider defining some features in `Cargo.toml`")]
|
||||
DefineFeatures,
|
||||
#[multipart_suggestion(
|
||||
"there is a similar config predicate: `version(\"..\")`",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
VersionSyntax {
|
||||
#[suggestion_part(code = "(")]
|
||||
between_name_and_value: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
after_value: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameAndValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and no value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameNoValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name and different values",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameDifferentValues {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
#[suggestion(
|
||||
"there is a config with a similar name",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
SimilarValues {
|
||||
#[subdiagnostic]
|
||||
with_similar_values: Vec<FoundWithSimilarValue>,
|
||||
#[subdiagnostic]
|
||||
expected_names: Option<ExpectedNames>,
|
||||
},
|
||||
#[suggestion(
|
||||
"you may have meant to use `{$literal}` (notice the capitalization). Doing so makes this predicate evaluate to `{$literal}` unconditionally",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose",
|
||||
code = "{literal}"
|
||||
)]
|
||||
BooleanLiteral {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
literal: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help("expected values for `{$best_match}` are: {$possibilities}")]
|
||||
pub(crate) struct ExpectedValues {
|
||||
pub best_match: Symbol,
|
||||
pub possibilities: DiagSymbolList,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"found config with similar value",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
pub(crate) struct FoundWithSimilarValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help_once(
|
||||
"expected names are: {$possibilities}{$and_more ->
|
||||
[0] {\"\"}
|
||||
*[other] {\" \"}and {$and_more} more
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct ExpectedNames {
|
||||
pub possibilities: DiagSymbolList<Ident>,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvocationHelp {
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgCargoHelp>,
|
||||
},
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: super::UnexpectedCfgRustcHelp,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"unexpected `cfg` condition value: {$has_value ->
|
||||
[true] `{$value}`
|
||||
*[false] (none)
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct UnexpectedCfgValue {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_value::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_value::InvocationHelp,
|
||||
|
||||
pub has_value: bool,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
pub(crate) mod unexpected_cfg_value {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CodeSuggestion {
|
||||
ChangeValue {
|
||||
#[subdiagnostic]
|
||||
expected_values: ExpectedValues,
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<ChangeValueSuggestion>,
|
||||
},
|
||||
#[note("no expected value for `{$name}`")]
|
||||
RemoveValue {
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<RemoveValueSuggestion>,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
#[note("no expected values for `{$name}`")]
|
||||
RemoveCondition {
|
||||
#[subdiagnostic]
|
||||
suggestion: RemoveConditionSuggestion,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
ChangeName {
|
||||
#[subdiagnostic]
|
||||
suggestions: Vec<ChangeNameSuggestion>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum ChangeValueSuggestion {
|
||||
#[suggestion(
|
||||
"there is a expected value with a similar name",
|
||||
code = r#""{best_match}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
best_match: Symbol,
|
||||
},
|
||||
#[suggestion(
|
||||
"specify a config value",
|
||||
code = r#" = "{first_possibility}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SpecifyValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
first_possibility: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("remove the value", code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) struct RemoveValueSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("remove the condition", code = "", applicability = "maybe-incorrect")]
|
||||
pub(crate) struct RemoveConditionSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(
|
||||
"expected values for `{$name}` are: {$have_none_possibility ->
|
||||
[true] {\"(none), \"}
|
||||
*[false] {\"\"}
|
||||
}{$possibilities}{$and_more ->
|
||||
[0] {\"\"}
|
||||
*[other] {\" \"}and {$and_more} more
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct ExpectedValues {
|
||||
pub name: Symbol,
|
||||
pub have_none_possibility: bool,
|
||||
pub possibilities: DiagSymbolList,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"`{$value}` is an expected value for `{$name}`",
|
||||
code = "{name}",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub(crate) struct ChangeNameSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
pub value: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvocationHelp {
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
help: Option<CargoHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
},
|
||||
#[note(
|
||||
"see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration"
|
||||
)]
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgRustcHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CargoHelp {
|
||||
#[help("consider adding `{$value}` as a feature in `Cargo.toml`")]
|
||||
AddFeature {
|
||||
value: Symbol,
|
||||
},
|
||||
#[help("consider defining some features in `Cargo.toml`")]
|
||||
DefineFeatures,
|
||||
Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("creating a {$shared_label}reference to mutable static")]
|
||||
pub(crate) struct RefOfMutStatic<'a> {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::def_id::DefPathHash;
|
||||
pub use rustc_span::edition::Edition;
|
||||
use rustc_span::{HashStableContext, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{HashStableContext, Ident, Symbol, sym};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use self::Level::*;
|
||||
@@ -652,12 +652,6 @@ pub enum DeprecatedSinceKind {
|
||||
InVersion(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AttributeLintKind {
|
||||
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
|
||||
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
|
||||
}
|
||||
|
||||
pub type RegisteredTools = FxIndexSet<Ident>;
|
||||
|
||||
/// Declares a static item of type `&'static Lint`.
|
||||
|
||||
@@ -344,7 +344,30 @@ pub fn dyn_buffer_lint<
|
||||
lint,
|
||||
Some(span.into()),
|
||||
node_id,
|
||||
DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn dyn_buffer_lint_sess<
|
||||
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
|
||||
+ DynSync
|
||||
+ DynSend
|
||||
+ 'static,
|
||||
>(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: impl Into<MultiSpan>,
|
||||
node_id: NodeId,
|
||||
callback: F,
|
||||
) {
|
||||
self.opt_span_buffer_lint(
|
||||
lint,
|
||||
Some(span.into()),
|
||||
node_id,
|
||||
DecorateDiagCompat(Box::new(|dcx, level, sess| {
|
||||
let sess = sess.downcast_ref::<Session>().expect("expected a `Session`");
|
||||
callback(dcx, level, sess)
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ LL | cfg_macro::my_lib_macro!();
|
||||
= help: expected names are: `feature` and 32 more
|
||||
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
|
||||
= help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg
|
||||
= help: the macro `cfg_macro::my_lib_macro` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
= note: this warning originates in the macro `cfg_macro::my_lib_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
@@ -21,7 +20,6 @@ LL | cfg_macro::my_lib_macro_value!();
|
||||
= note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind`
|
||||
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
|
||||
= help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg
|
||||
= help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
|
||||
= note: this warning originates in the macro `cfg_macro::my_lib_macro_value` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
@@ -34,7 +32,6 @@ LL | cfg_macro::my_lib_macro_feature!();
|
||||
= note: no expected values for `feature`
|
||||
= note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
|
||||
= help: try referring to `cfg_macro::my_lib_macro_feature` crate for guidance on how handle this unexpected cfg
|
||||
= help: the macro `cfg_macro::my_lib_macro_feature` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
|
||||
= note: this warning originates in the macro `cfg_macro::my_lib_macro_feature` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
|
||||
+1
-1
@@ -1053,7 +1053,7 @@ cc = ["@Nadrieril"]
|
||||
message = "Some changes occurred in cfg and check-cfg configuration"
|
||||
cc = ["@Urgau"]
|
||||
|
||||
[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"]
|
||||
[mentions."compiler/rustc_attr_parsing/src/attributes/diagnostic/check_cfg.rs"]
|
||||
message = "Some changes occurred in check-cfg diagnostics"
|
||||
cc = ["@Urgau"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user