blob: b76390c47ac4ff6aa50ac6a1d3a241e7fc995ddd [file] [edit]
use std::fmt;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, StableHash};
use rustc_span::{Symbol, sym};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "nightly", derive(StableHash, Encodable, Decodable))]
pub struct LintName {
/// The lint's tool name, if present.
pub tool: Option<Symbol>,
/// The lint's name, minus the tool name if any.
///
/// For example:
/// - `clippy::blah` -> `blah`
/// - `unstable_imports` -> `unstable_imports`
/// - `custom_tool::blah::bleh` -> `blah::bleh`
pub name: Symbol,
}
impl LintName {
pub fn new(segments: impl Iterator<Item = Symbol>) -> LintName {
let segments = segments.collect::<Vec<_>>();
let (tool, name) = match &*segments {
[] => unreachable!(),
[lint_name] => (None, *lint_name),
[tool, lint_name] => (Some(*tool), *lint_name),
// Not reachable for any builtin lints,
// but reachable using `register_tool`.
[tool, lint_name, rest @ ..] => {
let mut lint_name = String::from(lint_name.as_str());
for seg in rest {
lint_name.push_str("::");
lint_name.push_str(seg.as_str());
}
(Some(*tool), Symbol::intern(&lint_name))
}
};
LintName { tool, name }
}
/// `lint` must not be empty.
pub fn from_str(lint: &str) -> LintName {
if lint.is_empty() {
if cfg!(debug_assertions) {
rustc_span::bug!("`lint` is empty")
} else {
return LintName { tool: None, name: sym::empty };
}
}
if let Some((tool, name)) = lint.split_once("::") {
LintName { tool: Some(Symbol::intern(tool)), name: Symbol::intern(name) }
} else {
LintName { tool: None, name: Symbol::intern(lint) }
}
}
pub fn to_lowercase(mut self) -> LintName {
fn lowercase(s: &mut Symbol) {
let lower = s.as_str().to_lowercase();
*s = Symbol::intern(&lower);
}
if let Some(tool) = &mut self.tool {
lowercase(tool);
}
lowercase(&mut self.name);
self
}
pub fn is(&self, lint: Symbol) -> bool {
lint == self.name && self.tool.is_none()
}
}
impl fmt::Display for LintName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(tool) = self.tool {
write!(f, "{tool}::")?
}
write!(f, "{}", self.name)?;
Ok(())
}
}
#[cfg(feature = "nightly")]
impl rustc_error_messages::IntoDiagArg for LintName {
fn into_diag_arg(
self,
_: &mut Option<std::path::PathBuf>,
) -> rustc_error_messages::DiagArgValue {
self.to_string().into_diag_arg(&mut None)
}
}