mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 22:54:58 +00:00
internal: fix automatic rustc/rustdoc lint generation
This commit is contained in:
parent
b1f89a84ab
commit
c5d9bfaa52
2 changed files with 125 additions and 92 deletions
|
@ -55,37 +55,56 @@ pub struct LintGroup {
|
|||
sourcegen::ensure_file_contents(destination.as_path(), &contents);
|
||||
}
|
||||
|
||||
/// Parses the output of `rustdoc -Whelp` and prints `Lint` and `LintGroup` constants into `buf`.
|
||||
///
|
||||
/// As of writing, the output of `rustc -Whelp` (not rustdoc) has the following format:
|
||||
///
|
||||
/// ```text
|
||||
/// Lint checks provided by rustc:
|
||||
///
|
||||
/// name default meaning
|
||||
/// ---- ------- -------
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// Lint groups provided by rustc:
|
||||
///
|
||||
/// name sub-lints
|
||||
/// ---- ---------
|
||||
///
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// `rustdoc -Whelp` (and any other custom `rustc` driver) adds another two
|
||||
/// tables after the `rustc` ones, with a different title but the same format.
|
||||
fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
||||
// FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
|
||||
let file = project_root().join(file!());
|
||||
let stdout = cmd!(sh, "rustdoc -W help {file}").read().unwrap();
|
||||
let start_lints = stdout.find("---- ------- -------").unwrap();
|
||||
let start_lint_groups = stdout.find("---- ---------").unwrap();
|
||||
let start_lints_rustdoc =
|
||||
stdout.find("Lint checks provided by plugins loaded by this crate:").unwrap();
|
||||
let start_lint_groups_rustdoc =
|
||||
stdout.find("Lint groups provided by plugins loaded by this crate:").unwrap();
|
||||
let stdout = cmd!(sh, "rustdoc -Whelp").read().unwrap();
|
||||
let lints_pat = "---- ------- -------\n";
|
||||
let lint_groups_pat = "---- ---------\n";
|
||||
let lints = find_and_slice(&stdout, lints_pat);
|
||||
let lint_groups = find_and_slice(lints, lint_groups_pat);
|
||||
let lints_rustdoc = find_and_slice(lint_groups, lints_pat);
|
||||
let lint_groups_rustdoc = find_and_slice(lints_rustdoc, lint_groups_pat);
|
||||
|
||||
buf.push_str(r#"pub const DEFAULT_LINTS: &[Lint] = &["#);
|
||||
buf.push('\n');
|
||||
|
||||
let lints = stdout[start_lints..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
|
||||
let lints = lints.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
||||
(name.trim(), Cow::Borrowed(description.trim()), vec![])
|
||||
});
|
||||
let lint_groups =
|
||||
stdout[start_lint_groups..].lines().skip(1).take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
(
|
||||
name.trim(),
|
||||
format!("lint group for: {}", lints.trim()).into(),
|
||||
lints
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
||||
.collect(),
|
||||
)
|
||||
});
|
||||
let lint_groups = lint_groups.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
(
|
||||
name.trim(),
|
||||
format!("lint group for: {}", lints.trim()).into(),
|
||||
lints
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
||||
.collect(),
|
||||
)
|
||||
});
|
||||
|
||||
let lints = lints
|
||||
.chain(lint_groups)
|
||||
|
@ -94,7 +113,8 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
|||
for (name, description, ..) in &lints {
|
||||
push_lint_completion(buf, &name.replace('-', "_"), description);
|
||||
}
|
||||
buf.push_str("];\n");
|
||||
buf.push_str("];\n\n");
|
||||
|
||||
buf.push_str(r#"pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &["#);
|
||||
for (name, description, children) in &lints {
|
||||
if !children.is_empty() {
|
||||
|
@ -115,27 +135,23 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
|||
buf.push_str(r#"pub const RUSTDOC_LINTS: &[Lint] = &["#);
|
||||
buf.push('\n');
|
||||
|
||||
let lints_rustdoc =
|
||||
stdout[start_lints_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
let (_default_level, description) =
|
||||
rest.trim().split_once(char::is_whitespace).unwrap();
|
||||
(name.trim(), Cow::Borrowed(description.trim()), vec![])
|
||||
});
|
||||
let lints_rustdoc = lints_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, rest) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
let (_default_level, description) = rest.trim().split_once(char::is_whitespace).unwrap();
|
||||
(name.trim(), Cow::Borrowed(description.trim()), vec![])
|
||||
});
|
||||
let lint_groups_rustdoc =
|
||||
stdout[start_lint_groups_rustdoc..].lines().skip(2).take_while(|l| !l.is_empty()).map(
|
||||
|line| {
|
||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
(
|
||||
name.trim(),
|
||||
format!("lint group for: {}", lints.trim()).into(),
|
||||
lints
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
);
|
||||
lint_groups_rustdoc.lines().take_while(|l| !l.is_empty()).map(|line| {
|
||||
let (name, lints) = line.trim().split_once(char::is_whitespace).unwrap();
|
||||
(
|
||||
name.trim(),
|
||||
format!("lint group for: {}", lints.trim()).into(),
|
||||
lints
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.trim().trim_matches(',').replace('-', "_"))
|
||||
.collect(),
|
||||
)
|
||||
});
|
||||
|
||||
let lints_rustdoc = lints_rustdoc
|
||||
.chain(lint_groups_rustdoc)
|
||||
|
@ -145,7 +161,7 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
|||
for (name, description, ..) in &lints_rustdoc {
|
||||
push_lint_completion(buf, &name.replace('-', "_"), description)
|
||||
}
|
||||
buf.push_str("];\n");
|
||||
buf.push_str("];\n\n");
|
||||
|
||||
buf.push_str(r#"pub const RUSTDOC_LINT_GROUPS: &[LintGroup] = &["#);
|
||||
for (name, description, children) in &lints_rustdoc {
|
||||
|
@ -157,14 +173,24 @@ fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
|
|||
buf.push_str("];\n");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn find_and_slice<'a>(i: &'a str, p: &str) -> &'a str {
|
||||
let idx = i.find(p).unwrap();
|
||||
&i[idx + p.len()..]
|
||||
}
|
||||
|
||||
/// Parses the unstable book root directory at `src_dir` and prints a constant
|
||||
/// with the list of unstable features into `buf`.
|
||||
///
|
||||
/// It does this by looking for all `.md` files in the `language-features` and
|
||||
/// `library-features` directories, and using the file name as the feature
|
||||
/// name, and the file contents as the feature description.
|
||||
fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) {
|
||||
let mut features = ["language-features", "library-features"]
|
||||
.into_iter()
|
||||
.flat_map(|it| sourcegen::list_files(&src_dir.join(it)))
|
||||
.filter(|path| {
|
||||
// Get all `.md ` files
|
||||
path.extension().unwrap_or_default().to_str().unwrap_or_default() == "md"
|
||||
})
|
||||
// Get all `.md` files
|
||||
.filter(|path| path.extension() == Some("md".as_ref()))
|
||||
.map(|path| {
|
||||
let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace('-', "_");
|
||||
let doc = fs::read_to_string(path).unwrap();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue