aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/xtask/src/codegen/gen_lint_completions.rs b/xtask/src/codegen/gen_lint_completions.rs
new file mode 100644
index 000000000..cffe954f8
--- /dev/null
+++ b/xtask/src/codegen/gen_lint_completions.rs
@@ -0,0 +1,113 @@
1//! Generates descriptors structure for unstable feature from Unstable Book
2use std::path::{Path, PathBuf};
3
4use quote::quote;
5use walkdir::WalkDir;
6use xshell::{cmd, read_file};
7
8use crate::{
9 codegen::{project_root, reformat, update, Mode, Result},
10 run_rustfmt,
11};
12
13pub fn generate_lint_completions(mode: Mode) -> Result<()> {
14 if !Path::new("./target/rust").exists() {
15 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?;
16 }
17
18 let ts_features = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?;
19 cmd!("curl http://rust-lang.github.io/rust-clippy/master/lints.json --output ./target/clippy_lints.json").run()?;
20
21 let ts_clippy = generate_descriptor_clippy(&Path::new("./target/clippy_lints.json"))?;
22 let ts = quote! {
23 use crate::complete_attribute::LintCompletion;
24 #ts_features
25 #ts_clippy
26 };
27 let contents = reformat(ts.to_string().as_str())?;
28
29 let destination = project_root().join("crates/completion/src/generated_lint_completions.rs");
30 update(destination.as_path(), &contents, mode)?;
31 run_rustfmt(mode)?;
32
33 Ok(())
34}
35
36fn generate_descriptor(src_dir: PathBuf) -> Result<proc_macro2::TokenStream> {
37 let definitions = ["language-features", "library-features"]
38 .iter()
39 .flat_map(|it| WalkDir::new(src_dir.join(it)))
40 .filter_map(|e| e.ok())
41 .filter(|entry| {
42 // Get all `.md ` files
43 entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "md"
44 })
45 .map(|entry| {
46 let path = entry.path();
47 let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
48 let doc = read_file(path).unwrap();
49
50 quote! { LintCompletion { label: #feature_ident, description: #doc } }
51 });
52
53 let ts = quote! {
54 pub(super) const FEATURES: &[LintCompletion] = &[
55 #(#definitions),*
56 ];
57 };
58
59 Ok(ts)
60}
61
62#[derive(Default)]
63struct ClippyLint {
64 help: String,
65 id: String,
66}
67
68fn generate_descriptor_clippy(path: &Path) -> Result<proc_macro2::TokenStream> {
69 let file_content = read_file(path)?;
70 let mut clippy_lints: Vec<ClippyLint> = vec![];
71
72 for line in file_content.lines().map(|line| line.trim()) {
73 if line.starts_with(r#""id":"#) {
74 let clippy_lint = ClippyLint {
75 id: line
76 .strip_prefix(r#""id": ""#)
77 .expect("should be prefixed by id")
78 .strip_suffix(r#"","#)
79 .expect("should be suffixed by comma")
80 .into(),
81 help: String::new(),
82 };
83 clippy_lints.push(clippy_lint)
84 } else if line.starts_with(r#""What it does":"#) {
85 // Typical line to strip: "What is doest": "Here is my useful content",
86 let prefix_to_strip = r#""What it does": ""#;
87 let suffix_to_strip = r#"","#;
88
89 let clippy_lint = clippy_lints.last_mut().expect("clippy lint must already exist");
90 clippy_lint.help = line
91 .strip_prefix(prefix_to_strip)
92 .expect("should be prefixed by what it does")
93 .strip_suffix(suffix_to_strip)
94 .expect("should be suffixed by comma")
95 .into();
96 }
97 }
98
99 let definitions = clippy_lints.into_iter().map(|clippy_lint| {
100 let lint_ident = format!("clippy::{}", clippy_lint.id);
101 let doc = clippy_lint.help;
102
103 quote! { LintCompletion { label: #lint_ident, description: #doc } }
104 });
105
106 let ts = quote! {
107 pub(super) const CLIPPY_LINTS: &[LintCompletion] = &[
108 #(#definitions),*
109 ];
110 };
111
112 Ok(ts)
113}