Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions clippy_utils/src/msrvs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ impl Msrv {
self.current(cx).is_none_or(|msrv| msrv >= required)
}

/// Reads the MSRV from Cargo.toml and merges it with the existing configuration
///
/// This method checks the `CARGO_PACKAGE_RUST_VERSION` environment variable set by Cargo
/// and integrates it with the MSRV from `clippy.toml` according to these rules:
///
/// - If only Cargo.toml specifies an MSRV, it will be used
/// - If both Cargo.toml and clippy.toml specify an MSRV and they differ, a warning is emitted
/// and the value from `clippy.toml` takes precedence
/// - If neither specifies an MSRV, no change occurs
///
/// # Note
///
/// This should be called during lint pass initialization to ensure the MSRV from Cargo.toml
/// is properly considered alongside the clippy.toml configuration
pub fn read_cargo(&mut self, sess: &Session) {
Comment on lines +135 to 149
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is overly verbose and the function won't exist here after the config rewrite PR is merged.

let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
Expand Down Expand Up @@ -159,34 +173,55 @@ pub struct MsrvStack {
}

impl MsrvStack {
/// Creates a new `MsrvStack` with the initial MSRV value from configuration
pub fn new(initial: Msrv) -> Self {
Self {
stack: SmallVec::from_iter(initial.0),
}
}

/// Returns the MSRV at the current stack level
///
/// This represents the effective MSRV after applying any `#[clippy::msrv]` attributes
/// encountered during traversal
pub fn current(&self) -> Option<RustcVersion> {
self.stack.last().copied()
}

/// Checks if the current MSRV meets or exceeds the required version
///
/// Returns `true` if no MSRV is configured or if the current MSRV is greater than
/// or equal to the required version
Comment on lines +191 to +194
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be shortened to just "Checks if the current MSRV is either None, or is at least as high as the required version."

pub fn meets(&self, required: RustcVersion) -> bool {
self.current().is_none_or(|msrv| msrv >= required)
}

/// Processes attributes to update the MSRV stack when entering a new scope
///
/// If a `#[clippy::msrv]` attribute is found, parses the version and pushes it
/// onto the stack. Also marks that MSRV attributes have been seen globally.
Comment on lines +199 to +202
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be shortened to just "If the attributes contain a version attribute, pushes that version onto the stack."

A second paragraph about this being intended to be used from a lint pass's check_attributes function is also worth having.

pub fn check_attributes(&mut self, sess: &Session, attrs: &[Attribute]) {
if let Some(version) = parse_attrs(sess, attrs) {
SEEN_MSRV_ATTR.store(true, Ordering::Relaxed);
self.stack.push(version);
}
}

/// Processes attributes to update the MSRV stack when leaving a scope
///
/// If a `#[clippy::msrv]` attribute is found, pops the most recently pushed
/// MSRV from the stack, effectively restoring the previous MSRV level
Comment on lines +210 to +213
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be shortened to just "If the attributes contain a version attribute, pops a version from the stack."

A second paragraph about this being intended to be used from a lint pass's check_attributes_post function is also worth having.

pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[Attribute]) {
if parse_attrs(sess, attrs).is_some() {
self.stack.pop();
}
}
}

/// Parses attributes to extract MSRV versions from `#[clippy::msrv]` attributes
///
/// Returns the parsed Rust version if found, or `None` if no valid MSRV attribute is present.
/// Emits diagnostic errors for invalid versions or duplicate attributes.
fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> {
let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv]));

Expand Down
Loading