Minimizing changes

This commit is contained in:
blyxyas 2023-05-06 08:38:47 +02:00
parent f9c1d155b4
commit 2a4571d959
No known key found for this signature in database
GPG Key ID: 4D38170B5A2FC334
4 changed files with 168 additions and 112 deletions

View File

@ -331,8 +331,11 @@
mod zero_sized_map_values; mod zero_sized_map_values;
// end lints modules, do not remove this comment, its used in `update_lints` // end lints modules, do not remove this comment, its used in `update_lints`
use crate::utils::conf::{format_error, TryConf};
pub use crate::utils::conf::{lookup_conf_file, Conf}; pub use crate::utils::conf::{lookup_conf_file, Conf};
use crate::utils::{
conf::{format_error, metadata::get_configuration_metadata, TryConf},
FindAll,
};
/// Register all pre expansion lints /// Register all pre expansion lints
/// ///
@ -388,7 +391,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>
conf conf
} }
#[derive(Default)] #[derive(Default)] //~ ERROR no such field
struct RegistrationGroups { struct RegistrationGroups {
all: Vec<LintId>, all: Vec<LintId>,
cargo: Vec<LintId>, cargo: Vec<LintId>,
@ -471,7 +474,22 @@ pub(crate) struct LintInfo {
pub fn explain(name: &str) { pub fn explain(name: &str) {
let target = format!("clippy::{}", name.to_ascii_uppercase()); let target = format!("clippy::{}", name.to_ascii_uppercase());
match declared_lints::LINTS.iter().find(|info| info.lint.name == target) { match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
Some(info) => print!("{}", info.explanation), Some(info) => {
println!("{}", info.explanation);
// Check if the lint has configuration
let mdconf = get_configuration_metadata();
if let Some(config_vec_positions) = mdconf
.iter()
.find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
{
// If it has, print it
println!("### Configuration for {}:", info.lint.name_lower());
for position in config_vec_positions {
let conf = &mdconf[position];
println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default);
}
}
},
None => println!("unknown lint: {name}"), None => println!("unknown lint: {name}"),
} }
} }

View File

@ -174,16 +174,15 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
} }
} }
#[cfg(feature = "internal")]
pub mod metadata { pub mod metadata {
use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; use crate::utils::ClippyConfiguration;
macro_rules! wrap_option { macro_rules! wrap_option {
() => (None); () => (None);
($x:literal) => (Some($x)); ($x:literal) => (Some($x));
} }
pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
vec![ vec![
$( $(
{ {

View File

@ -8,7 +8,11 @@
//! a simple mistake) //! a simple mistake)
use crate::renamed_lints::RENAMED_LINTS; use crate::renamed_lints::RENAMED_LINTS;
use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; use crate::utils::{
collect_configs,
internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type},
ClippyConfiguration,
};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@ -520,111 +524,6 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
} }
} }
// ==================================================================
// Configuration
// ==================================================================
#[derive(Debug, Clone, Default)]
pub struct ClippyConfiguration {
name: String,
config_type: &'static str,
default: String,
lints: Vec<String>,
doc: String,
#[allow(dead_code)]
deprecation_reason: Option<&'static str>,
}
impl ClippyConfiguration {
pub fn new(
name: &'static str,
config_type: &'static str,
default: String,
doc_comment: &'static str,
deprecation_reason: Option<&'static str>,
) -> Self {
let (lints, doc) = parse_config_field_doc(doc_comment)
.unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
Self {
name: to_kebab(name),
lints,
doc,
config_type,
default,
deprecation_reason,
}
}
fn to_markdown_paragraph(&self) -> String {
format!(
"### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
self.name,
self.doc
.lines()
.map(|line| line.strip_prefix(" ").unwrap_or(line))
.join("\n"),
self.default,
self.config_type,
self.lints
.iter()
.map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
.map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
.join("\n"),
)
}
fn to_markdown_table_entry(&self) -> String {
format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
}
}
fn collect_configs() -> Vec<ClippyConfiguration> {
crate::utils::conf::metadata::get_configuration_metadata()
}
/// This parses the field documentation of the config struct.
///
/// ```rust, ignore
/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
/// ```
///
/// Would yield:
/// ```rust, ignore
/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
/// ```
fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
const DOC_START: &str = " Lint: ";
if_chain! {
if doc_comment.starts_with(DOC_START);
if let Some(split_pos) = doc_comment.find('.');
then {
let mut doc_comment = doc_comment.to_string();
let mut documentation = doc_comment.split_off(split_pos);
// Extract lints
doc_comment.make_ascii_lowercase();
let lints: Vec<String> = doc_comment
.split_off(DOC_START.len())
.split(", ")
.map(str::to_string)
.collect();
// Format documentation correctly
// split off leading `.` from lint name list and indent for correct formatting
documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
Some((lints, documentation))
} else {
None
}
}
}
/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
fn to_kebab(config_name: &str) -> String {
config_name.replace('_', "-")
}
impl fmt::Display for ClippyConfiguration { impl fmt::Display for ClippyConfiguration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
writeln!( writeln!(

View File

@ -4,3 +4,143 @@
pub mod format_args_collector; pub mod format_args_collector;
#[cfg(feature = "internal")] #[cfg(feature = "internal")]
pub mod internal_lints; pub mod internal_lints;
#[cfg(feature = "internal")]
use itertools::Itertools;
/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
fn to_kebab(config_name: &str) -> String {
config_name.replace('_', "-")
}
// ==================================================================
// Configuration
// ==================================================================
#[derive(Debug, Clone, Default)] //~ ERROR no such field
pub struct ClippyConfiguration {
pub name: String,
#[allow(dead_code)]
config_type: &'static str,
pub default: String,
pub lints: Vec<String>,
pub doc: String,
#[allow(dead_code)]
deprecation_reason: Option<&'static str>,
}
impl ClippyConfiguration {
pub fn new(
name: &'static str,
config_type: &'static str,
default: String,
doc_comment: &'static str,
deprecation_reason: Option<&'static str>,
) -> Self {
let (lints, doc) = parse_config_field_doc(doc_comment)
.unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
Self {
name: to_kebab(name),
lints,
doc,
config_type,
default,
deprecation_reason,
}
}
#[cfg(feature = "internal")]
fn to_markdown_paragraph(&self) -> String {
format!(
"### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
self.name,
self.doc
.lines()
.map(|line| line.strip_prefix(" ").unwrap_or(line))
.join("\n"),
self.default,
self.config_type,
self.lints
.iter()
.map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
.map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
.join("\n"),
)
}
#[cfg(feature = "internal")]
fn to_markdown_table_entry(&self) -> String {
format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
}
}
#[cfg(feature = "internal")]
fn collect_configs() -> Vec<ClippyConfiguration> {
crate::utils::conf::metadata::get_configuration_metadata()
}
/// This parses the field documentation of the config struct.
///
/// ```rust, ignore
/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
/// ```
///
/// Would yield:
/// ```rust, ignore
/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
/// ```
fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
const DOC_START: &str = " Lint: ";
if_chain! {
if doc_comment.starts_with(DOC_START);
if let Some(split_pos) = doc_comment.find('.');
then {
let mut doc_comment = doc_comment.to_string();
let mut documentation = doc_comment.split_off(split_pos);
// Extract lints
doc_comment.make_ascii_lowercase();
let lints: Vec<String> = doc_comment
.split_off(DOC_START.len())
.split(", ")
.map(str::to_string)
.collect();
// Format documentation correctly
// split off leading `.` from lint name list and indent for correct formatting
documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
Some((lints, documentation))
} else {
None
}
}
}
// Shamelessly stolen from find_all (https://github.com/nectariner/find_all)
pub trait FindAll: Iterator + Sized {
fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>>
where
P: FnMut(&Self::Item) -> bool;
}
impl<I> FindAll for I
where
I: Iterator,
{
fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>>
where
P: FnMut(&Self::Item) -> bool,
{
let mut occurences = Vec::<usize>::default();
for (index, element) in self.enumerate() {
if predicate(&element) {
occurences.push(index);
}
}
match occurences.len() {
0 => None,
_ => Some(occurences),
}
}
}