diff options
Diffstat (limited to 'compiler/rustc_lint/src/context.rs')
-rw-r--r-- | compiler/rustc_lint/src/context.rs | 146 |
1 files changed, 79 insertions, 67 deletions
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index a5f4c5ff0..c7a9d5e80 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, Ty use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; -use rustc_session::Session; +use rustc_session::{LintStoreMarker, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; @@ -77,6 +77,8 @@ pub struct LintStore { lint_groups: FxHashMap<&'static str, LintGroup>, } +impl LintStoreMarker for LintStore {} + /// The target of the `by_name` map, which accounts for renaming/deprecation. #[derive(Debug)] enum TargetLint { @@ -385,7 +387,7 @@ impl LintStore { }; } Some(LintGroup { lint_ids, .. }) => { - return CheckLintNameResult::Tool(Ok(&lint_ids)); + return CheckLintNameResult::Tool(Ok(lint_ids)); } }, Some(Id(id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))), @@ -406,12 +408,12 @@ impl LintStore { if let Some(LintAlias { name, silent }) = depr { let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); return if *silent { - CheckLintNameResult::Ok(&lint_ids) + CheckLintNameResult::Ok(lint_ids) } else { - CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string()))) + CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string()))) }; } - CheckLintNameResult::Ok(&lint_ids) + CheckLintNameResult::Ok(lint_ids) } }, Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)), @@ -458,12 +460,12 @@ impl LintStore { if let Some(LintAlias { name, silent }) = depr { let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); return if *silent { - CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) + CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name))) } else { - CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string()))) + CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string()))) }; } - CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) + CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name))) } }, Some(Id(id)) => { @@ -497,9 +499,6 @@ pub struct LateContext<'tcx> { /// Items accessible from the crate being checked. pub effective_visibilities: &'tcx EffectiveVisibilities, - /// The store of registered lints and the lint levels. - pub lint_store: &'tcx LintStore, - pub last_node_with_lint_attrs: hir::HirId, /// Generic type parameters in scope for the item we are in. @@ -515,21 +514,11 @@ pub struct EarlyContext<'a> { pub buffered: LintBuffer, } -pub trait LintPassObject: Sized {} - -impl LintPassObject for EarlyLintPassObject {} - -impl LintPassObject for LateLintPassObject<'_> {} - -pub trait LintContext: Sized { - type PassObject: LintPassObject; - +pub trait LintContext { fn sess(&self) -> &Session; - fn lints(&self) -> &LintStore; - /// Emit a lint at the appropriate level, with an optional associated span and an existing diagnostic. - /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. + /// Emit a lint at the appropriate level, with an optional associated span and an existing + /// diagnostic. /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] @@ -538,9 +527,7 @@ pub trait LintContext: Sized { lint: &'static Lint, span: Option<impl Into<MultiSpan>>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), diagnostic: BuiltinLintDiagnostics, ) { // We first generate a blank diagnostic. @@ -713,10 +700,14 @@ pub trait LintContext: Sized { db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); }, BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => { - let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect(); + let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().copied().collect(); + let is_from_cargo = std::env::var_os("CARGO").is_some(); + let mut is_feature_cfg = name == sym::feature; + if is_feature_cfg && is_from_cargo { + db.help("consider defining some features in `Cargo.toml`"); // Suggest the most probable if we found one - if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { + } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { if let Some(ExpectedValues::Some(best_match_values)) = sess.parse_sess.check_config.expecteds.get(&best_match) { let mut possibilities = best_match_values.iter() @@ -749,6 +740,8 @@ pub trait LintContext: Sized { } else { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } + + is_feature_cfg |= best_match == sym::feature; } else if !possibilities.is_empty() { let mut possibilities = possibilities.iter() .map(Symbol::as_str) @@ -762,6 +755,23 @@ pub trait LintContext: Sized { // once. db.help_once(format!("expected names are: `{possibilities}`")); } + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if !is_feature_cfg { + db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); + } else { + db.help(format!("to expect this configuration use `--check-cfg={inst}`")); + db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); + } }, BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else { @@ -773,6 +783,7 @@ pub trait LintContext: Sized { .copied() .flatten() .collect(); + let is_from_cargo = std::env::var_os("CARGO").is_some(); // 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 @@ -793,6 +804,8 @@ pub trait LintContext: Sized { db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect); } + } else if name == sym::feature && is_from_cargo { + db.help(format!("consider defining `{name}` as feature in `Cargo.toml`")); } else if let &[first_possibility] = &possibilities[..] { db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect); } @@ -802,6 +815,27 @@ pub trait LintContext: Sized { db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect); } } + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if name == sym::feature { + if let Some((value, _value_span)) = value { + db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); + } + } else { + db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration"); + } else { + db.help(format!("to expect this configuration use `--check-cfg={inst}`")); + db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); + } }, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { db.multipart_suggestion( @@ -932,6 +966,10 @@ pub trait LintContext: Sized { if elided { "'static " } else { "'static" }, Applicability::MachineApplicable ); + }, + BuiltinLintDiagnostics::RedundantImportVisibility { max_vis, span } => { + db.span_note(span, format!("the most public imported item is `{max_vis}`")); + db.help("reduce the glob import's visibility or increase visibility of imported items"); } } // Rewrap `db`, and pass control to the user. @@ -943,8 +981,6 @@ pub trait LintContext: Sized { // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn lookup<S: Into<MultiSpan>>( @@ -952,9 +988,7 @@ pub trait LintContext: Sized { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ); /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, @@ -965,13 +999,13 @@ pub trait LintContext: Sized { span: S, decorator: impl for<'a> DecorateLint<'a, ()>, ) { - self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag)); + self.lookup(lint, Some(span), decorator.msg(), |diag| { + decorator.decorate_lint(diag); + }); } /// Emit a lint at the appropriate level, with an associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn struct_span_lint<S: Into<MultiSpan>>( @@ -979,9 +1013,7 @@ pub trait LintContext: Sized { lint: &'static Lint, span: S, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.lookup(lint, Some(span), msg, decorate); } @@ -990,23 +1022,19 @@ pub trait LintContext: Sized { /// generated by `#[derive(LintDiagnostic)]`). fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| { - decorator.decorate_lint(diag) + decorator.decorate_lint(diag); }); } /// Emit a lint at the appropriate level, with no associated span. /// - /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation. - /// /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature #[rustc_lint_diagnostics] fn lint( &self, lint: &'static Lint, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.lookup(lint, None as Option<Span>, msg, decorate); } @@ -1059,15 +1087,9 @@ impl<'a> EarlyContext<'a> { } impl<'tcx> LintContext for LateContext<'tcx> { - type PassObject = LateLintPassObject<'tcx>; - /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { - &self.tcx.sess - } - - fn lints(&self) -> &LintStore { - &*self.lint_store + self.tcx.sess } #[rustc_lint_diagnostics] @@ -1076,9 +1098,7 @@ impl<'tcx> LintContext for LateContext<'tcx> { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { let hir_id = self.last_node_with_lint_attrs; @@ -1094,15 +1114,9 @@ impl<'tcx> LintContext for LateContext<'tcx> { } impl LintContext for EarlyContext<'_> { - type PassObject = EarlyLintPassObject; - /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { - &self.builder.sess() - } - - fn lints(&self) -> &LintStore { - self.builder.lint_store() + self.builder.sess() } #[rustc_lint_diagnostics] @@ -1111,9 +1125,7 @@ impl LintContext for EarlyContext<'_> { lint: &'static Lint, span: Option<S>, msg: impl Into<DiagnosticMessage>, - decorate: impl for<'a, 'b> FnOnce( - &'b mut DiagnosticBuilder<'a, ()>, - ) -> &'b mut DiagnosticBuilder<'a, ()>, + decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>), ) { self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate) } @@ -1149,7 +1161,7 @@ impl<'tcx> LateContext<'tcx> { /// bodies (e.g. for paths in `hir::Ty`), without any risk of ICE-ing. pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { - hir::QPath::Resolved(_, ref path) => path.res, + hir::QPath::Resolved(_, path) => path.res, hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results() .filter(|typeck_results| typeck_results.hir_owner == id.owner) |