aboutsummaryrefslogtreecommitdiff
path: root/xtask
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-10-20 20:43:44 +0100
committerGitHub <[email protected]>2020-10-20 20:43:44 +0100
commit08823c82627540d42de055112eaf8745c694ff47 (patch)
treec78e34fbda9795c0671c71661a6c63faaf596a3b /xtask
parentc00339509d27061f77dac5eef33335095afea8ec (diff)
parentaa031e91f4f809933eb967edda256ebf6b8bf4ea (diff)
Merge #6109
6109: add completions for clippy lint in attributes r=bnjjj a=bnjjj Co-authored-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'xtask')
-rw-r--r--xtask/src/codegen.rs6
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs113
-rw-r--r--xtask/tests/tidy.rs10
3 files changed, 125 insertions, 4 deletions
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index afa703471..adea053b6 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -9,7 +9,7 @@ mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs; 11mod gen_feature_docs;
12mod gen_features; 12mod gen_lint_completions;
13mod gen_diagnostic_docs; 13mod gen_diagnostic_docs;
14 14
15use std::{ 15use std::{
@@ -24,7 +24,7 @@ pub use self::{
24 gen_assists_docs::{generate_assists_docs, generate_assists_tests}, 24 gen_assists_docs::{generate_assists_docs, generate_assists_tests},
25 gen_diagnostic_docs::generate_diagnostic_docs, 25 gen_diagnostic_docs::generate_diagnostic_docs,
26 gen_feature_docs::generate_feature_docs, 26 gen_feature_docs::generate_feature_docs,
27 gen_features::generate_features, 27 gen_lint_completions::generate_lint_completions,
28 gen_parser_tests::generate_parser_tests, 28 gen_parser_tests::generate_parser_tests,
29 gen_syntax::generate_syntax, 29 gen_syntax::generate_syntax,
30}; 30};
@@ -42,7 +42,7 @@ pub struct CodegenCmd {
42impl CodegenCmd { 42impl CodegenCmd {
43 pub fn run(self) -> Result<()> { 43 pub fn run(self) -> Result<()> {
44 if self.features { 44 if self.features {
45 generate_features(Mode::Overwrite)?; 45 generate_lint_completions(Mode::Overwrite)?;
46 } 46 }
47 generate_syntax(Mode::Overwrite)?; 47 generate_syntax(Mode::Overwrite)?;
48 generate_parser_tests(Mode::Overwrite)?; 48 generate_parser_tests(Mode::Overwrite)?;
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}
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index faaef2fd4..9de60c76c 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -131,6 +131,14 @@ https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-
131} 131}
132 132
133fn deny_clippy(path: &PathBuf, text: &String) { 133fn deny_clippy(path: &PathBuf, text: &String) {
134 let ignore = &[
135 // The documentation in string literals may contain anything for its own purposes
136 "completion/src/generated_lint_completions.rs",
137 ];
138 if ignore.iter().any(|p| path.ends_with(p)) {
139 return;
140 }
141
134 if text.contains("[\u{61}llow(clippy") { 142 if text.contains("[\u{61}llow(clippy") {
135 panic!( 143 panic!(
136 "\n\nallowing lints is forbidden: {}. 144 "\n\nallowing lints is forbidden: {}.
@@ -214,7 +222,7 @@ fn check_todo(path: &Path, text: &str) {
214 // `ast::make`. 222 // `ast::make`.
215 "ast/make.rs", 223 "ast/make.rs",
216 // The documentation in string literals may contain anything for its own purposes 224 // The documentation in string literals may contain anything for its own purposes
217 "completion/src/generated_features.rs", 225 "completion/src/generated_lint_completions.rs",
218 ]; 226 ];
219 if need_todo.iter().any(|p| path.ends_with(p)) { 227 if need_todo.iter().any(|p| path.ends_with(p)) {
220 return; 228 return;