Skip to content

Commit

Permalink
Suppress nightly lint emission in Clippy
Browse files Browse the repository at this point in the history
  • Loading branch information
xFrednet committed Feb 14, 2022
1 parent bc43b89 commit 56a5ba9
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 5 deletions.
35 changes: 35 additions & 0 deletions clippy_dev/src/update_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ pub fn run(update_mode: UpdateMode) {
update_mode,
&gen_deprecated(deprecated_lints.iter()),
);
process_file(
"clippy_lints/src/lib.nightly_lints.rs",
update_mode,
&gen_nightly_lint_list(internal_lints.iter(), usable_lints.iter()),
);

let all_group_lints = usable_lints.iter().filter(|l| {
matches!(
Expand Down Expand Up @@ -320,6 +325,36 @@ fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> String {
output
}

fn gen_nightly_lint_list<'a>(
internal_lints: impl Iterator<Item = &'a Lint>,
usable_lints: impl Iterator<Item = &'a Lint>,
) -> String {
let details: Vec<_> = internal_lints
.map(|l| (false, l))
.chain(usable_lints.map(|l| (true, l)))
.filter(|(_, l)| l.version.as_ref().map_or(false, |v| v == "nightly"))
.map(|(p, l)| (p, &l.module, l.name.to_uppercase()))
.collect();

let mut output = GENERATED_FILE_COMMENT.to_string();
output.push_str("clippy_utils::nightly::set_nightly_lints([\n");
// The test lint "FOREVER_NIGHTLY_LINT" is in the `internal_warn` group which is
// not processed by `update_lints`. For testing purposes we still need the lint to be
// registered in the `nightly_lints` list. This manually adds this one lint.
output.push_str(" #[cfg(feature = \"internal\")]\n");
output.push_str(" LintId::of(utils::internal_lints::FOREVER_NIGHTLY_LINT),\n");

for (is_public, module_name, lint_name) in details {
if !is_public {
output.push_str(" #[cfg(feature = \"internal\")]\n");
}
output.push_str(&format!(" LintId::of({}::{}),\n", module_name, lint_name));
}
output.push_str("])\n");

output
}

/// Generates the code for registering lints
#[must_use]
fn gen_register_lint_list<'a>(
Expand Down
12 changes: 12 additions & 0 deletions clippy_lints/src/lib.nightly_lints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This file was generated by `cargo dev update_lints`.
// Use that command to update this file and do not edit by hand.
// Manual edits will be overwritten.

clippy_utils::nightly::set_nightly_lints([
#[cfg(feature = "internal")]
LintId::of(utils::internal_lints::FOREVER_NIGHTLY_LINT),
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
LintId::of(borrow_as_ptr::BORROW_AS_PTR),
LintId::of(manual_bits::MANUAL_BITS),
LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
])
1 change: 1 addition & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
register_removed_non_tool_lints(store);

include!("lib.deprecated.rs");
include!("lib.nightly_lints.rs");

include!("lib.register_lints.rs");
include!("lib.register_restriction.rs");
Expand Down
32 changes: 27 additions & 5 deletions clippy_utils/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
//! Thank you!
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
use crate::nightly::LintLevelProvider;

use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
Expand Down Expand Up @@ -46,7 +48,11 @@ fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
/// 17 | std::mem::forget(seven);
/// | ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
pub fn span_lint<T: LintContext + LintLevelProvider>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
if crate::nightly::suppress_lint(cx, lint) {
return;
}

cx.struct_span_lint(lint, sp, |diag| {
let mut diag = diag.build(msg);
docs_link(&mut diag, lint);
Expand Down Expand Up @@ -74,7 +80,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
/// |
/// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
pub fn span_lint_and_help<'a, T: LintContext + LintLevelProvider>(
cx: &'a T,
lint: &'static Lint,
span: Span,
Expand Down Expand Up @@ -117,14 +123,18 @@ pub fn span_lint_and_help<'a, T: LintContext>(
/// 10 | forget(&SomeStruct);
/// | ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
pub fn span_lint_and_note<'a, T: LintContext + LintLevelProvider>(
cx: &'a T,
lint: &'static Lint,
span: impl Into<MultiSpan>,
msg: &str,
note_span: Option<Span>,
note: &str,
) {
if crate::nightly::suppress_lint(cx, lint) {
return;
}

cx.struct_span_lint(lint, span, |diag| {
let mut diag = diag.build(msg);
if let Some(note_span) = note_span {
Expand All @@ -143,10 +153,14 @@ pub fn span_lint_and_note<'a, T: LintContext>(
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
where
C: LintContext,
C: LintContext + LintLevelProvider,
S: Into<MultiSpan>,
F: FnOnce(&mut DiagnosticBuilder<'_>),
{
if crate::nightly::suppress_lint(cx, lint) {
return;
}

cx.struct_span_lint(lint, sp, |diag| {
let mut diag = diag.build(msg);
f(&mut diag);
Expand All @@ -156,6 +170,10 @@ where
}

pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
if crate::nightly::suppress_lint(cx, lint) {
return;
}

cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
let mut diag = diag.build(msg);
docs_link(&mut diag, lint);
Expand All @@ -171,6 +189,10 @@ pub fn span_lint_hir_and_then(
msg: &str,
f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
if crate::nightly::suppress_lint(cx, lint) {
return;
}

cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
let mut diag = diag.build(msg);
f(&mut diag);
Expand Down Expand Up @@ -199,7 +221,7 @@ pub fn span_lint_hir_and_then(
/// = note: `-D fold-any` implied by `-D warnings`
/// ```
#[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))]
pub fn span_lint_and_sugg<'a, T: LintContext>(
pub fn span_lint_and_sugg<'a, T: LintContext + LintLevelProvider>(
cx: &'a T,
lint: &'static Lint,
sp: Span,
Expand Down
66 changes: 66 additions & 0 deletions clippy_utils/src/nightly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
use std::lazy::SyncOnceCell;

use rustc_data_structures::stable_set::FxHashSet;
use rustc_lint::{EarlyContext, LateContext, Level, Lint, LintId};
use rustc_middle::lint::{LevelAndSource, LintLevelSource};
use rustc_session::Session;

static IS_NIGHTLY_RUN: SyncOnceCell<bool> = SyncOnceCell::new();
static NIGHTLY_LINTS: SyncOnceCell<FxHashSet<LintId>> = SyncOnceCell::new();

/// This function is used to determine if nightly lints should be enabled or disabled
/// in this Clippy run.
Expand Down Expand Up @@ -33,3 +37,65 @@ pub fn eval_is_nightly_run(sess: &Session) {
pub fn is_nightly_run() -> bool {
*IS_NIGHTLY_RUN.get().unwrap_or(&false)
}

/// This function takes a list of all nightly lints that will be surpressed before
/// the emission if nightly lints are disabled.
///
/// It's only allowed to call this once. This is done by [`clippy_lints::lib`]
#[doc(hidden)]
pub fn set_nightly_lints<const N: usize>(lints: [LintId; N]) {
// The from trait for HashMaps is only implemented for the normal hasher. Here we have to add each
// item individually
let mut nightly_lints = FxHashSet::default();
lints.iter().copied().for_each(|lint| {
nightly_lints.insert(lint);
});
NIGHTLY_LINTS
.set(nightly_lints)
.expect("`NIGHTLY_LINTS` should only be set once.");
}

/// Returns true if the lint is a registered nightly lint. Note that a lint will still be a
/// registered nightly lint if nightly lints are enabled as usual.
///
/// Please use [`is_nightly_run`] to determine if Clippy's nightly features
/// should be enabled.
#[inline]
pub fn is_nightly_lint(lint: &'static Lint) -> bool {
NIGHTLY_LINTS
.get()
.map_or(false, |lints| lints.contains(&LintId::of(lint)))
}

/// This function checks if the given lint is a nightly lint and should be suppressed in the current
/// context.
pub fn suppress_lint<T: LintLevelProvider>(cx: &T, lint: &'static Lint) -> bool {
if !is_nightly_run() && is_nightly_lint(lint) {
let (_, level_src) = cx.get_lint_level(lint);
if level_src == LintLevelSource::Default
|| level_src == LintLevelSource::CommandLine(sym!(warnings), Level::Deny)
{
return true;
}
}

false
}

/// This trait is used to retrieve the lint level for the lint based on the
/// current linting context.
pub trait LintLevelProvider {
fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource;
}

impl LintLevelProvider for LateContext<'_> {
fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs)
}
}

impl LintLevelProvider for EarlyContext<'_> {
fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource {
self.builder.lint_level(lint)
}
}

0 comments on commit 56a5ba9

Please sign in to comment.