aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-08 18:52:08 +0000
committerGitHub <[email protected]>2021-03-08 18:52:08 +0000
commit8b7e82b012c417ec40a896203ad79f20cf5530ef (patch)
tree85413766cc45708d77dfa9cb5a3a00767af8461a
parent071dde1c1da10e3580bded99dc2d529074356536 (diff)
parentd2bb2268d3a9cc0e2a6970c85c45724af5eb255c (diff)
Merge #7918
7918: Generalize file ensuring infrastructure r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/rust-analyzer/src/config.rs15
-rw-r--r--crates/syntax/src/tests.rs6
-rw-r--r--crates/test_utils/src/bench_fixture.rs6
-rw-r--r--crates/test_utils/src/lib.rs44
-rw-r--r--docs/dev/architecture.md3
-rw-r--r--xtask/src/codegen.rs78
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs20
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs8
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs8
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs12
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs12
-rw-r--r--xtask/src/codegen/gen_syntax.rs10
-rw-r--r--xtask/src/flags.rs10
-rw-r--r--xtask/src/main.rs15
-rw-r--r--xtask/src/release.rs5
-rw-r--r--xtask/src/tidy.rs50
16 files changed, 158 insertions, 144 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 4dbabdba7..078c83f75 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -859,12 +859,12 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
859mod tests { 859mod tests {
860 use std::fs; 860 use std::fs;
861 861
862 use test_utils::project_dir; 862 use test_utils::{ensure_file_contents, project_root};
863 863
864 use super::*; 864 use super::*;
865 865
866 #[test] 866 #[test]
867 fn schema_in_sync_with_package_json() { 867 fn generate_package_json_config() {
868 let s = Config::json_schema(); 868 let s = Config::json_schema();
869 let schema = format!("{:#}", s); 869 let schema = format!("{:#}", s);
870 let mut schema = schema 870 let mut schema = schema
@@ -877,7 +877,7 @@ mod tests {
877 .to_string(); 877 .to_string();
878 schema.push_str(",\n"); 878 schema.push_str(",\n");
879 879
880 let package_json_path = project_dir().join("editors/code/package.json"); 880 let package_json_path = project_root().join("editors/code/package.json");
881 let mut package_json = fs::read_to_string(&package_json_path).unwrap(); 881 let mut package_json = fs::read_to_string(&package_json_path).unwrap();
882 882
883 let start_marker = " \"$generated-start\": false,\n"; 883 let start_marker = " \"$generated-start\": false,\n";
@@ -885,19 +885,18 @@ mod tests {
885 885
886 let start = package_json.find(start_marker).unwrap() + start_marker.len(); 886 let start = package_json.find(start_marker).unwrap() + start_marker.len();
887 let end = package_json.find(end_marker).unwrap(); 887 let end = package_json.find(end_marker).unwrap();
888
888 let p = remove_ws(&package_json[start..end]); 889 let p = remove_ws(&package_json[start..end]);
889 let s = remove_ws(&schema); 890 let s = remove_ws(&schema);
890
891 if !p.contains(&s) { 891 if !p.contains(&s) {
892 package_json.replace_range(start..end, &schema); 892 package_json.replace_range(start..end, &schema);
893 fs::write(&package_json_path, &mut package_json).unwrap(); 893 ensure_file_contents(&package_json_path, &package_json)
894 panic!("new config, updating package.json")
895 } 894 }
896 } 895 }
897 896
898 #[test] 897 #[test]
899 fn schema_in_sync_with_docs() { 898 fn generate_config_documentation() {
900 let docs_path = project_dir().join("docs/user/generated_config.adoc"); 899 let docs_path = project_root().join("docs/user/generated_config.adoc");
901 let current = fs::read_to_string(&docs_path).unwrap(); 900 let current = fs::read_to_string(&docs_path).unwrap();
902 let expected = ConfigData::manual(); 901 let expected = ConfigData::manual();
903 902
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index b2c06e24f..ba0ccfaed 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -7,7 +7,7 @@ use std::{
7use ast::NameOwner; 7use ast::NameOwner;
8use expect_test::expect_file; 8use expect_test::expect_file;
9use rayon::prelude::*; 9use rayon::prelude::*;
10use test_utils::{bench, bench_fixture, project_dir, skip_slow_tests}; 10use test_utils::{bench, bench_fixture, project_root, skip_slow_tests};
11 11
12use crate::{ast, fuzz, tokenize, AstNode, SourceFile, SyntaxError, TextRange, TextSize, Token}; 12use crate::{ast, fuzz, tokenize, AstNode, SourceFile, SyntaxError, TextRange, TextSize, Token};
13 13
@@ -153,7 +153,7 @@ fn reparse_fuzz_tests() {
153/// Test that Rust-analyzer can parse and validate the rust-analyzer 153/// Test that Rust-analyzer can parse and validate the rust-analyzer
154#[test] 154#[test]
155fn self_hosting_parsing() { 155fn self_hosting_parsing() {
156 let dir = project_dir().join("crates"); 156 let dir = project_root().join("crates");
157 let files = walkdir::WalkDir::new(dir) 157 let files = walkdir::WalkDir::new(dir)
158 .into_iter() 158 .into_iter()
159 .filter_entry(|entry| { 159 .filter_entry(|entry| {
@@ -193,7 +193,7 @@ fn self_hosting_parsing() {
193} 193}
194 194
195fn test_data_dir() -> PathBuf { 195fn test_data_dir() -> PathBuf {
196 project_dir().join("crates/syntax/test_data") 196 project_root().join("crates/syntax/test_data")
197} 197}
198 198
199fn assert_errors_are_present(errors: &[SyntaxError], path: &Path) { 199fn assert_errors_are_present(errors: &[SyntaxError], path: &Path) {
diff --git a/crates/test_utils/src/bench_fixture.rs b/crates/test_utils/src/bench_fixture.rs
index d775e2cc9..3a37c4473 100644
--- a/crates/test_utils/src/bench_fixture.rs
+++ b/crates/test_utils/src/bench_fixture.rs
@@ -4,7 +4,7 @@ use std::fs;
4 4
5use stdx::format_to; 5use stdx::format_to;
6 6
7use crate::project_dir; 7use crate::project_root;
8 8
9pub fn big_struct() -> String { 9pub fn big_struct() -> String {
10 let n = 1_000; 10 let n = 1_000;
@@ -32,11 +32,11 @@ struct S{} {{
32} 32}
33 33
34pub fn glorious_old_parser() -> String { 34pub fn glorious_old_parser() -> String {
35 let path = project_dir().join("bench_data/glorious_old_parser"); 35 let path = project_root().join("bench_data/glorious_old_parser");
36 fs::read_to_string(&path).unwrap() 36 fs::read_to_string(&path).unwrap()
37} 37}
38 38
39pub fn numerous_macro_rules() -> String { 39pub fn numerous_macro_rules() -> String {
40 let path = project_dir().join("bench_data/numerous_macro_rules"); 40 let path = project_root().join("bench_data/numerous_macro_rules");
41 fs::read_to_string(&path).unwrap() 41 fs::read_to_string(&path).unwrap()
42} 42}
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 27b05e34b..6041ab5e4 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -14,11 +14,11 @@ mod fixture;
14use std::{ 14use std::{
15 convert::{TryFrom, TryInto}, 15 convert::{TryFrom, TryInto},
16 env, fs, 16 env, fs,
17 path::PathBuf, 17 path::{Path, PathBuf},
18}; 18};
19 19
20use profile::StopWatch; 20use profile::StopWatch;
21use stdx::lines_with_ends; 21use stdx::{is_ci, lines_with_ends};
22use text_size::{TextRange, TextSize}; 22use text_size::{TextRange, TextSize};
23 23
24pub use dissimilar::diff as __diff; 24pub use dissimilar::diff as __diff;
@@ -288,14 +288,14 @@ pub fn skip_slow_tests() -> bool {
288 if should_skip { 288 if should_skip {
289 eprintln!("ignoring slow test") 289 eprintln!("ignoring slow test")
290 } else { 290 } else {
291 let path = project_dir().join("./target/.slow_tests_cookie"); 291 let path = project_root().join("./target/.slow_tests_cookie");
292 fs::write(&path, ".").unwrap(); 292 fs::write(&path, ".").unwrap();
293 } 293 }
294 should_skip 294 should_skip
295} 295}
296 296
297/// Returns the path to the root directory of `rust-analyzer` project. 297/// Returns the path to the root directory of `rust-analyzer` project.
298pub fn project_dir() -> PathBuf { 298pub fn project_root() -> PathBuf {
299 let dir = env!("CARGO_MANIFEST_DIR"); 299 let dir = env!("CARGO_MANIFEST_DIR");
300 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned() 300 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
301} 301}
@@ -353,3 +353,39 @@ pub fn bench(label: &'static str) -> impl Drop {
353 353
354 Bencher { sw: StopWatch::start(), label } 354 Bencher { sw: StopWatch::start(), label }
355} 355}
356
357/// Checks that the `file` has the specified `contents`. If that is not the
358/// case, updates the file and then fails the test.
359pub fn ensure_file_contents(file: &Path, contents: &str) {
360 if let Err(()) = try_ensure_file_contents(file, contents) {
361 panic!("Some files were not up-to-date");
362 }
363}
364
365/// Checks that the `file` has the specified `contents`. If that is not the
366/// case, updates the file and return an Error.
367pub fn try_ensure_file_contents(file: &Path, contents: &str) -> Result<(), ()> {
368 match std::fs::read_to_string(file) {
369 Ok(old_contents) if normalize_newlines(&old_contents) == normalize_newlines(contents) => {
370 return Ok(())
371 }
372 _ => (),
373 }
374 let display_path = file.strip_prefix(&project_root()).unwrap_or(file);
375 eprintln!(
376 "\n\x1b[31;1merror\x1b[0m: {} was not up-to-date, updating\n",
377 display_path.display()
378 );
379 if is_ci() {
380 eprintln!(" NOTE: run `cargo test` locally and commit the updated files\n");
381 }
382 if let Some(parent) = file.parent() {
383 let _ = std::fs::create_dir_all(parent);
384 }
385 std::fs::write(file, contents).unwrap();
386 Err(())
387}
388
389fn normalize_newlines(s: &str) -> String {
390 s.replace("\r\n", "\n")
391}
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index ead12616e..0a3fd4285 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -308,9 +308,8 @@ This sections talks about the things which are everywhere and nowhere in particu
308### Code generation 308### Code generation
309 309
310Some of the components of this repository are generated through automatic processes. 310Some of the components of this repository are generated through automatic processes.
311`cargo xtask codegen` runs all generation tasks. 311Generated code is updated automatically on `cargo test`.
312Generated code is generally committed to the git repository. 312Generated code is generally committed to the git repository.
313There are tests to check that the generated code is fresh.
314 313
315In particular, we generate: 314In particular, we generate:
316 315
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 2f56c5ad0..2cf3c6fdc 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -7,68 +7,66 @@
7 7
8mod gen_syntax; 8mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_lint_completions;
10mod gen_assists_docs; 11mod gen_assists_docs;
11mod gen_feature_docs; 12mod gen_feature_docs;
12mod gen_lint_completions;
13mod gen_diagnostic_docs; 13mod gen_diagnostic_docs;
14 14
15use std::{ 15use std::{
16 fmt, mem, 16 fmt, mem,
17 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
18}; 18};
19use xshell::{cmd, pushenv, read_file, write_file}; 19use xshell::{cmd, pushenv};
20 20
21use crate::{ensure_rustfmt, flags, project_root, Result}; 21use crate::{ensure_rustfmt, project_root, Result};
22 22
23pub(crate) use self::{ 23pub(crate) use self::{
24 gen_assists_docs::{generate_assists_docs, generate_assists_tests}, 24 gen_assists_docs::generate_assists_tests, gen_lint_completions::generate_lint_completions,
25 gen_diagnostic_docs::generate_diagnostic_docs, 25 gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax,
26 gen_feature_docs::generate_feature_docs,
27 gen_lint_completions::generate_lint_completions,
28 gen_parser_tests::generate_parser_tests,
29 gen_syntax::generate_syntax,
30}; 26};
31 27
32#[derive(Debug, PartialEq, Eq, Clone, Copy)] 28pub(crate) fn docs() -> Result<()> {
33pub(crate) enum Mode { 29 // We don't commit docs to the repo, so we can just overwrite them.
34 Overwrite, 30 gen_assists_docs::generate_assists_docs()?;
35 Verify, 31 gen_feature_docs::generate_feature_docs()?;
32 gen_diagnostic_docs::generate_diagnostic_docs()?;
33 Ok(())
36} 34}
37 35
38impl flags::Codegen { 36#[allow(unused)]
39 pub(crate) fn run(self) -> Result<()> { 37fn used() {
40 if self.features { 38 generate_parser_tests();
41 generate_lint_completions(Mode::Overwrite)?; 39 generate_assists_tests();
42 } 40 generate_syntax();
43 generate_syntax(Mode::Overwrite)?; 41 generate_lint_completions();
44 generate_parser_tests(Mode::Overwrite)?;
45 generate_assists_tests(Mode::Overwrite)?;
46 generate_assists_docs(Mode::Overwrite)?;
47 generate_feature_docs(Mode::Overwrite)?;
48 generate_diagnostic_docs(Mode::Overwrite)?;
49 Ok(())
50 }
51} 42}
52 43
53/// A helper to update file on disk if it has changed. 44/// Checks that the `file` has the specified `contents`. If that is not the
54/// With verify = false, 45/// case, updates the file and then fails the test.
55fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { 46pub(crate) fn ensure_file_contents(file: &Path, contents: &str) -> Result<()> {
56 match read_file(path) { 47 match std::fs::read_to_string(file) {
57 Ok(old_contents) if normalize(&old_contents) == normalize(contents) => { 48 Ok(old_contents) if normalize_newlines(&old_contents) == normalize_newlines(contents) => {
58 return Ok(()); 49 return Ok(())
59 } 50 }
60 _ => (), 51 _ => (),
61 } 52 }
62 if mode == Mode::Verify { 53 let display_path = file.strip_prefix(&project_root()).unwrap_or(file);
63 anyhow::bail!("`{}` is not up-to-date", path.display()); 54 eprintln!(
55 "\n\x1b[31;1merror\x1b[0m: {} was not up-to-date, updating\n",
56 display_path.display()
57 );
58 if std::env::var("CI").is_ok() {
59 eprintln!(" NOTE: run `cargo test` locally and commit the updated files\n");
64 } 60 }
65 eprintln!("updating {}", path.display()); 61 if let Some(parent) = file.parent() {
66 write_file(path, contents)?; 62 let _ = std::fs::create_dir_all(parent);
67 return Ok(());
68
69 fn normalize(s: &str) -> String {
70 s.replace("\r\n", "\n")
71 } 63 }
64 std::fs::write(file, contents).unwrap();
65 anyhow::bail!("some file were not up to date")
66}
67
68fn normalize_newlines(s: &str) -> String {
69 s.replace("\r\n", "\n")
72} 70}
73 71
74const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/codegen`"; 72const PREAMBLE: &str = "Generated file, do not edit by hand, see `xtask/src/codegen`";
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index c469b388d..158680993 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -2,22 +2,25 @@
2 2
3use std::{fmt, path::Path}; 3use std::{fmt, path::Path};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, reformat, Location, Mode, PREAMBLE}, 8 codegen::{self, extract_comment_blocks_with_empty_lines, reformat, Location, PREAMBLE},
7 project_root, rust_files_in, Result, 9 project_root, rust_files_in, Result,
8}; 10};
9 11
10pub(crate) fn generate_assists_tests(mode: Mode) -> Result<()> { 12pub(crate) fn generate_assists_tests() -> Result<()> {
11 let assists = Assist::collect()?; 13 let assists = Assist::collect()?;
12 generate_tests(&assists, mode) 14 generate_tests(&assists)
13} 15}
14 16
15pub(crate) fn generate_assists_docs(mode: Mode) -> Result<()> { 17pub(crate) fn generate_assists_docs() -> Result<()> {
16 let assists = Assist::collect()?; 18 let assists = Assist::collect()?;
17 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 19 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
18 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 20 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
19 let dst = project_root().join("docs/user/generated_assists.adoc"); 21 let dst = project_root().join("docs/user/generated_assists.adoc");
20 codegen::update(&dst, &contents, mode) 22 write_file(dst, &contents)?;
23 Ok(())
21} 24}
22 25
23#[derive(Debug)] 26#[derive(Debug)]
@@ -111,7 +114,7 @@ impl fmt::Display for Assist {
111 } 114 }
112} 115}
113 116
114fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { 117fn generate_tests(assists: &[Assist]) -> Result<()> {
115 let mut buf = String::from("use super::check_doc_test;\n"); 118 let mut buf = String::from("use super::check_doc_test;\n");
116 119
117 for assist in assists.iter() { 120 for assist in assists.iter() {
@@ -135,7 +138,10 @@ r#####"
135 buf.push_str(&test) 138 buf.push_str(&test)
136 } 139 }
137 let buf = reformat(&buf)?; 140 let buf = reformat(&buf)?;
138 codegen::update(&project_root().join("crates/ide_assists/src/tests/generated.rs"), &buf, mode) 141 codegen::ensure_file_contents(
142 &project_root().join("crates/ide_assists/src/tests/generated.rs"),
143 &buf,
144 )
139} 145}
140 146
141fn hide_hash_comments(text: &str) -> String { 147fn hide_hash_comments(text: &str) -> String {
diff --git a/xtask/src/codegen/gen_diagnostic_docs.rs b/xtask/src/codegen/gen_diagnostic_docs.rs
index a2561817b..9cf4d0a88 100644
--- a/xtask/src/codegen/gen_diagnostic_docs.rs
+++ b/xtask/src/codegen/gen_diagnostic_docs.rs
@@ -2,18 +2,20 @@
2 2
3use std::{fmt, path::PathBuf}; 3use std::{fmt, path::PathBuf};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE}, 8 codegen::{extract_comment_blocks_with_empty_lines, Location, PREAMBLE},
7 project_root, rust_files, Result, 9 project_root, rust_files, Result,
8}; 10};
9 11
10pub(crate) fn generate_diagnostic_docs(mode: Mode) -> Result<()> { 12pub(crate) fn generate_diagnostic_docs() -> Result<()> {
11 let diagnostics = Diagnostic::collect()?; 13 let diagnostics = Diagnostic::collect()?;
12 let contents = 14 let contents =
13 diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 15 diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
14 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 16 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
15 let dst = project_root().join("docs/user/generated_diagnostic.adoc"); 17 let dst = project_root().join("docs/user/generated_diagnostic.adoc");
16 codegen::update(&dst, &contents, mode)?; 18 write_file(&dst, &contents)?;
17 Ok(()) 19 Ok(())
18} 20}
19 21
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs
index cad7ff477..c373d7d70 100644
--- a/xtask/src/codegen/gen_feature_docs.rs
+++ b/xtask/src/codegen/gen_feature_docs.rs
@@ -2,17 +2,19 @@
2 2
3use std::{fmt, path::PathBuf}; 3use std::{fmt, path::PathBuf};
4 4
5use xshell::write_file;
6
5use crate::{ 7use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode, PREAMBLE}, 8 codegen::{extract_comment_blocks_with_empty_lines, Location, PREAMBLE},
7 project_root, rust_files, Result, 9 project_root, rust_files, Result,
8}; 10};
9 11
10pub(crate) fn generate_feature_docs(mode: Mode) -> Result<()> { 12pub(crate) fn generate_feature_docs() -> Result<()> {
11 let features = Feature::collect()?; 13 let features = Feature::collect()?;
12 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); 14 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
13 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim()); 15 let contents = format!("//{}\n{}\n", PREAMBLE, contents.trim());
14 let dst = project_root().join("docs/user/generated_features.adoc"); 16 let dst = project_root().join("docs/user/generated_features.adoc");
15 codegen::update(&dst, &contents, mode)?; 17 write_file(&dst, &contents)?;
16 Ok(()) 18 Ok(())
17} 19}
18 20
diff --git a/xtask/src/codegen/gen_lint_completions.rs b/xtask/src/codegen/gen_lint_completions.rs
index b1c057037..24dbc6a39 100644
--- a/xtask/src/codegen/gen_lint_completions.rs
+++ b/xtask/src/codegen/gen_lint_completions.rs
@@ -5,13 +5,10 @@ use std::path::{Path, PathBuf};
5use walkdir::WalkDir; 5use walkdir::WalkDir;
6use xshell::{cmd, read_file}; 6use xshell::{cmd, read_file};
7 7
8use crate::{ 8use crate::codegen::{ensure_file_contents, project_root, reformat, Result};
9 codegen::{project_root, reformat, update, Mode, Result},
10 run_rustfmt,
11};
12 9
13pub(crate) fn generate_lint_completions(mode: Mode) -> Result<()> { 10pub(crate) fn generate_lint_completions() -> Result<()> {
14 if !Path::new("./target/rust").exists() { 11 if !project_root().join("./target/rust").exists() {
15 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?; 12 cmd!("git clone --depth=1 https://github.com/rust-lang/rust ./target/rust").run()?;
16 } 13 }
17 14
@@ -25,8 +22,7 @@ pub(crate) fn generate_lint_completions(mode: Mode) -> Result<()> {
25 22
26 let destination = 23 let destination =
27 project_root().join("crates/ide_completion/src/generated_lint_completions.rs"); 24 project_root().join("crates/ide_completion/src/generated_lint_completions.rs");
28 update(destination.as_path(), &contents, mode)?; 25 ensure_file_contents(destination.as_path(), &contents)?;
29 run_rustfmt(mode)?;
30 26
31 Ok(()) 27 Ok(())
32} 28}
diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs
index cb8939063..096590653 100644
--- a/xtask/src/codegen/gen_parser_tests.rs
+++ b/xtask/src/codegen/gen_parser_tests.rs
@@ -8,13 +8,13 @@ use std::{
8}; 8};
9 9
10use crate::{ 10use crate::{
11 codegen::{extract_comment_blocks, update, Mode}, 11 codegen::{ensure_file_contents, extract_comment_blocks},
12 project_root, Result, 12 project_root, Result,
13}; 13};
14 14
15pub(crate) fn generate_parser_tests(mode: Mode) -> Result<()> { 15pub(crate) fn generate_parser_tests() -> Result<()> {
16 let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?; 16 let tests = tests_from_dir(&project_root().join(Path::new("crates/parser/src/grammar")))?;
17 fn install_tests(tests: &HashMap<String, Test>, into: &str, mode: Mode) -> Result<()> { 17 fn install_tests(tests: &HashMap<String, Test>, into: &str) -> Result<()> {
18 let tests_dir = project_root().join(into); 18 let tests_dir = project_root().join(into);
19 if !tests_dir.is_dir() { 19 if !tests_dir.is_dir() {
20 fs::create_dir_all(&tests_dir)?; 20 fs::create_dir_all(&tests_dir)?;
@@ -35,12 +35,12 @@ pub(crate) fn generate_parser_tests(mode: Mode) -> Result<()> {
35 tests_dir.join(file_name) 35 tests_dir.join(file_name)
36 } 36 }
37 }; 37 };
38 update(&path, &test.text, mode)?; 38 ensure_file_contents(&path, &test.text)?;
39 } 39 }
40 Ok(()) 40 Ok(())
41 } 41 }
42 install_tests(&tests.ok, "crates/syntax/test_data/parser/inline/ok", mode)?; 42 install_tests(&tests.ok, "crates/syntax/test_data/parser/inline/ok")?;
43 install_tests(&tests.err, "crates/syntax/test_data/parser/inline/err", mode) 43 install_tests(&tests.err, "crates/syntax/test_data/parser/inline/err")
44} 44}
45 45
46#[derive(Debug)] 46#[derive(Debug)]
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 191bc0e9d..80f26e8f5 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -14,25 +14,25 @@ use ungrammar::{rust_grammar, Grammar, Rule};
14 14
15use crate::{ 15use crate::{
16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
17 codegen::{reformat, update, Mode}, 17 codegen::{ensure_file_contents, reformat},
18 project_root, Result, 18 project_root, Result,
19}; 19};
20 20
21pub(crate) fn generate_syntax(mode: Mode) -> Result<()> { 21pub(crate) fn generate_syntax() -> Result<()> {
22 let grammar = rust_grammar(); 22 let grammar = rust_grammar();
23 let ast = lower(&grammar); 23 let ast = lower(&grammar);
24 24
25 let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs"); 25 let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
26 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 26 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
27 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 27 ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds)?;
28 28
29 let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs"); 29 let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
30 let contents = generate_tokens(&ast)?; 30 let contents = generate_tokens(&ast)?;
31 update(ast_tokens_file.as_path(), &contents, mode)?; 31 ensure_file_contents(ast_tokens_file.as_path(), &contents)?;
32 32
33 let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs"); 33 let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
34 let contents = generate_nodes(KINDS_SRC, &ast)?; 34 let contents = generate_nodes(KINDS_SRC, &ast)?;
35 update(ast_nodes_file.as_path(), &contents, mode)?; 35 ensure_file_contents(ast_nodes_file.as_path(), &contents)?;
36 36
37 Ok(()) 37 Ok(())
38} 38}
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index b39d937ca..48d1ad45e 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -27,10 +27,6 @@ xflags::xflags! {
27 optional --jemalloc 27 optional --jemalloc
28 } 28 }
29 29
30 cmd codegen {
31 optional --features
32 }
33
34 cmd lint {} 30 cmd lint {}
35 cmd fuzz-tests {} 31 cmd fuzz-tests {}
36 cmd pre-cache {} 32 cmd pre-cache {}
@@ -67,7 +63,6 @@ pub struct Xtask {
67pub enum XtaskCmd { 63pub enum XtaskCmd {
68 Help(Help), 64 Help(Help),
69 Install(Install), 65 Install(Install),
70 Codegen(Codegen),
71 Lint(Lint), 66 Lint(Lint),
72 FuzzTests(FuzzTests), 67 FuzzTests(FuzzTests),
73 PreCache(PreCache), 68 PreCache(PreCache),
@@ -93,11 +88,6 @@ pub struct Install {
93} 88}
94 89
95#[derive(Debug)] 90#[derive(Debug)]
96pub struct Codegen {
97 pub features: bool,
98}
99
100#[derive(Debug)]
101pub struct Lint; 91pub struct Lint;
102 92
103#[derive(Debug)] 93#[derive(Debug)]
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 3c4332f75..35cc7c108 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -28,7 +28,7 @@ use std::{
28use walkdir::{DirEntry, WalkDir}; 28use walkdir::{DirEntry, WalkDir};
29use xshell::{cmd, cp, pushd, pushenv}; 29use xshell::{cmd, cp, pushd, pushenv};
30 30
31use crate::{codegen::Mode, dist::DistCmd}; 31use crate::dist::DistCmd;
32 32
33fn main() -> Result<()> { 33fn main() -> Result<()> {
34 let _d = pushd(project_root())?; 34 let _d = pushd(project_root())?;
@@ -40,7 +40,6 @@ fn main() -> Result<()> {
40 return Ok(()); 40 return Ok(());
41 } 41 }
42 flags::XtaskCmd::Install(cmd) => cmd.run(), 42 flags::XtaskCmd::Install(cmd) => cmd.run(),
43 flags::XtaskCmd::Codegen(cmd) => cmd.run(),
44 flags::XtaskCmd::Lint(_) => run_clippy(), 43 flags::XtaskCmd::Lint(_) => run_clippy(),
45 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), 44 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
46 flags::XtaskCmd::PreCache(cmd) => cmd.run(), 45 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
@@ -85,18 +84,6 @@ fn rust_files_in(path: &Path) -> impl Iterator<Item = PathBuf> {
85 files_in(path, "rs") 84 files_in(path, "rs")
86} 85}
87 86
88fn run_rustfmt(mode: Mode) -> Result<()> {
89 let _dir = pushd(project_root())?;
90 let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
91 ensure_rustfmt()?;
92 let check = match mode {
93 Mode::Overwrite => &[][..],
94 Mode::Verify => &["--", "--check"],
95 };
96 cmd!("cargo fmt {check...}").run()?;
97 Ok(())
98}
99
100fn ensure_rustfmt() -> Result<()> { 87fn ensure_rustfmt() -> Result<()> {
101 let out = cmd!("rustfmt --version").read()?; 88 let out = cmd!("rustfmt --version").read()?;
102 if !out.contains("stable") { 89 if !out.contains("stable") {
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index d8d86fd63..dde5d14ee 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -2,7 +2,7 @@ use std::fmt::Write;
2 2
3use xshell::{cmd, cp, pushd, read_dir, write_file}; 3use xshell::{cmd, cp, pushd, read_dir, write_file};
4 4
5use crate::{codegen, date_iso, flags, is_release_tag, project_root, Mode, Result}; 5use crate::{codegen, date_iso, flags, is_release_tag, project_root, Result};
6 6
7impl flags::Release { 7impl flags::Release {
8 pub(crate) fn run(self) -> Result<()> { 8 pub(crate) fn run(self) -> Result<()> {
@@ -12,8 +12,7 @@ impl flags::Release {
12 cmd!("git reset --hard tags/nightly").run()?; 12 cmd!("git reset --hard tags/nightly").run()?;
13 cmd!("git push").run()?; 13 cmd!("git push").run()?;
14 } 14 }
15 codegen::generate_assists_docs(Mode::Overwrite)?; 15 codegen::docs()?;
16 codegen::generate_feature_docs(Mode::Overwrite)?;
17 16
18 let website_root = project_root().join("../rust-analyzer.github.io"); 17 let website_root = project_root().join("../rust-analyzer.github.io");
19 let changelog_dir = website_root.join("./thisweek/_posts"); 18 let changelog_dir = website_root.join("./thisweek/_posts");
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index 349ca14d0..1352d1218 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -3,48 +3,48 @@ use std::{
3 path::{Path, PathBuf}, 3 path::{Path, PathBuf},
4}; 4};
5 5
6use xshell::{cmd, read_file}; 6use xshell::{cmd, pushd, pushenv, read_file};
7 7
8use crate::{ 8use crate::{cargo_files, codegen, project_root, rust_files};
9 cargo_files,
10 codegen::{self, Mode},
11 project_root, run_rustfmt, rust_files,
12};
13 9
14#[test] 10#[test]
15fn generated_grammar_is_fresh() { 11fn generate_grammar() {
16 if let Err(error) = codegen::generate_syntax(Mode::Verify) { 12 codegen::generate_syntax().unwrap()
17 panic!("{}. Please update it by running `cargo xtask codegen`", error);
18 }
19} 13}
20 14
21#[test] 15#[test]
22fn generated_tests_are_fresh() { 16fn generate_parser_tests() {
23 if let Err(error) = codegen::generate_parser_tests(Mode::Verify) { 17 codegen::generate_parser_tests().unwrap()
24 panic!("{}. Please update tests by running `cargo xtask codegen`", error);
25 }
26} 18}
27 19
28#[test] 20#[test]
29fn generated_assists_are_fresh() { 21fn generate_assists_tests() {
30 if let Err(error) = codegen::generate_assists_tests(Mode::Verify) { 22 codegen::generate_assists_tests().unwrap();
31 panic!("{}. Please update assists by running `cargo xtask codegen`", error); 23}
32 } 24
25/// This clones rustc repo, and so is not worth to keep up-to-date. We update
26/// manually by un-ignoring the test from time to time.
27#[test]
28#[ignore]
29fn generate_lint_completions() {
30 codegen::generate_lint_completions().unwrap()
33} 31}
34 32
35#[test] 33#[test]
36fn check_code_formatting() { 34fn check_code_formatting() {
37 if let Err(error) = run_rustfmt(Mode::Verify) { 35 let _dir = pushd(project_root()).unwrap();
38 panic!("{}. Please format the code by running `cargo format`", error); 36 let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
37 crate::ensure_rustfmt().unwrap();
38 let res = cmd!("cargo fmt -- --check").run();
39 if !res.is_ok() {
40 let _ = cmd!("cargo fmt").run();
39 } 41 }
42 res.unwrap()
40} 43}
41 44
42#[test] 45#[test]
43fn smoke_test_docs_generation() { 46fn smoke_test_generate_documentation() {
44 // We don't commit docs to the repo, so we can just overwrite in tests. 47 codegen::docs().unwrap()
45 codegen::generate_assists_docs(Mode::Overwrite).unwrap();
46 codegen::generate_feature_docs(Mode::Overwrite).unwrap();
47 codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
48} 48}
49 49
50#[test] 50#[test]