diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 23 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 17 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/text_tree_sink.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/tests.rs | 84 |
5 files changed, 67 insertions, 66 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 49696ce75..670f04578 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "666.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "669.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
@@ -31,4 +31,6 @@ serde = { version = "1.0.106", features = ["derive"] } | |||
31 | 31 | ||
32 | [dev-dependencies] | 32 | [dev-dependencies] |
33 | test_utils = { path = "../test_utils" } | 33 | test_utils = { path = "../test_utils" } |
34 | expect = { path = "../expect" } | ||
34 | walkdir = "2.3.1" | 35 | walkdir = "2.3.1" |
36 | rayon = "1" | ||
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 2ef173a03..abc7a646c 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -189,6 +189,21 @@ impl ast::RecordFieldList { | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | impl ast::TypeAliasDef { | ||
193 | #[must_use] | ||
194 | pub fn remove_bounds(&self) -> ast::TypeAliasDef { | ||
195 | let colon = match self.colon_token() { | ||
196 | Some(it) => it, | ||
197 | None => return self.clone(), | ||
198 | }; | ||
199 | let end = match self.type_bound_list() { | ||
200 | Some(it) => it.syntax().clone().into(), | ||
201 | None => colon.clone().into(), | ||
202 | }; | ||
203 | self.replace_children(colon.into()..=end, iter::empty()) | ||
204 | } | ||
205 | } | ||
206 | |||
192 | impl ast::TypeParam { | 207 | impl ast::TypeParam { |
193 | #[must_use] | 208 | #[must_use] |
194 | pub fn remove_bounds(&self) -> ast::TypeParam { | 209 | pub fn remove_bounds(&self) -> ast::TypeParam { |
@@ -299,12 +314,8 @@ impl ast::UseTree { | |||
299 | Some(it) => it, | 314 | Some(it) => it, |
300 | None => return self.clone(), | 315 | None => return self.clone(), |
301 | }; | 316 | }; |
302 | let use_tree = make::use_tree( | 317 | let use_tree = |
303 | suffix.clone(), | 318 | make::use_tree(suffix, self.use_tree_list(), self.alias(), self.star_token().is_some()); |
304 | self.use_tree_list(), | ||
305 | self.alias(), | ||
306 | self.star_token().is_some(), | ||
307 | ); | ||
308 | let nested = make::use_tree_list(iter::once(use_tree)); | 319 | let nested = make::use_tree_list(iter::once(use_tree)); |
309 | return make::use_tree(prefix.clone(), Some(nested), None, false); | 320 | return make::use_tree(prefix.clone(), Some(nested), None, false); |
310 | 321 | ||
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 2e72d4927..045f69133 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! There are many AstNodes, but only a few tokens, so we hand-write them here. | 1 | //! There are many AstNodes, but only a few tokens, so we hand-write them here. |
2 | 2 | ||
3 | use std::convert::{TryFrom, TryInto}; | 3 | use std::{ |
4 | borrow::Cow, | ||
5 | convert::{TryFrom, TryInto}, | ||
6 | }; | ||
4 | 7 | ||
5 | use crate::{ | 8 | use crate::{ |
6 | ast::{AstToken, Comment, RawString, String, Whitespace}, | 9 | ast::{AstToken, Comment, RawString, String, Whitespace}, |
@@ -138,11 +141,11 @@ impl HasQuotes for String {} | |||
138 | impl HasQuotes for RawString {} | 141 | impl HasQuotes for RawString {} |
139 | 142 | ||
140 | pub trait HasStringValue: HasQuotes { | 143 | pub trait HasStringValue: HasQuotes { |
141 | fn value(&self) -> Option<std::string::String>; | 144 | fn value(&self) -> Option<Cow<'_, str>>; |
142 | } | 145 | } |
143 | 146 | ||
144 | impl HasStringValue for String { | 147 | impl HasStringValue for String { |
145 | fn value(&self) -> Option<std::string::String> { | 148 | fn value(&self) -> Option<Cow<'_, str>> { |
146 | let text = self.text().as_str(); | 149 | let text = self.text().as_str(); |
147 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 150 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
148 | 151 | ||
@@ -156,15 +159,17 @@ impl HasStringValue for String { | |||
156 | if has_error { | 159 | if has_error { |
157 | return None; | 160 | return None; |
158 | } | 161 | } |
159 | Some(buf) | 162 | // FIXME: don't actually allocate for borrowed case |
163 | let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) }; | ||
164 | Some(res) | ||
160 | } | 165 | } |
161 | } | 166 | } |
162 | 167 | ||
163 | impl HasStringValue for RawString { | 168 | impl HasStringValue for RawString { |
164 | fn value(&self) -> Option<std::string::String> { | 169 | fn value(&self) -> Option<Cow<'_, str>> { |
165 | let text = self.text().as_str(); | 170 | let text = self.text().as_str(); |
166 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; | 171 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; |
167 | Some(text.to_string()) | 172 | Some(Cow::Borrowed(text)) |
168 | } | 173 | } |
169 | } | 174 | } |
170 | 175 | ||
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs index 22aed1db1..c6b30a02a 100644 --- a/crates/ra_syntax/src/parsing/text_tree_sink.rs +++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs | |||
@@ -160,7 +160,10 @@ fn n_attached_trivias<'a>( | |||
160 | if let Some((peek_kind, peek_text)) = | 160 | if let Some((peek_kind, peek_text)) = |
161 | trivias.peek().map(|(_, pair)| pair) | 161 | trivias.peek().map(|(_, pair)| pair) |
162 | { | 162 | { |
163 | if *peek_kind == COMMENT && peek_text.starts_with("///") { | 163 | if *peek_kind == COMMENT |
164 | && peek_text.starts_with("///") | ||
165 | && !peek_text.starts_with("////") | ||
166 | { | ||
164 | continue; | 167 | continue; |
165 | } | 168 | } |
166 | } | 169 | } |
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs index 7b4232497..8447dcad7 100644 --- a/crates/ra_syntax/src/tests.rs +++ b/crates/ra_syntax/src/tests.rs | |||
@@ -1,11 +1,12 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | env, | ||
3 | fmt::Write, | 2 | fmt::Write, |
4 | fs, | 3 | fs, |
5 | path::{Component, Path, PathBuf}, | 4 | path::{Path, PathBuf}, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use test_utils::{assert_eq_text, project_dir}; | 7 | use expect::expect_file; |
8 | use rayon::prelude::*; | ||
9 | use test_utils::project_dir; | ||
9 | 10 | ||
10 | use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token}; | 11 | use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token}; |
11 | 12 | ||
@@ -121,33 +122,43 @@ fn reparse_fuzz_tests() { | |||
121 | /// FIXME: Use this as a benchmark | 122 | /// FIXME: Use this as a benchmark |
122 | #[test] | 123 | #[test] |
123 | fn self_hosting_parsing() { | 124 | fn self_hosting_parsing() { |
124 | use std::ffi::OsStr; | ||
125 | let dir = project_dir().join("crates"); | 125 | let dir = project_dir().join("crates"); |
126 | let mut count = 0; | 126 | let files = walkdir::WalkDir::new(dir) |
127 | for entry in walkdir::WalkDir::new(dir) | ||
128 | .into_iter() | 127 | .into_iter() |
129 | .filter_entry(|entry| { | 128 | .filter_entry(|entry| { |
130 | !entry.path().components().any(|component| { | 129 | // Get all files which are not in the crates/ra_syntax/test_data folder |
131 | // Get all files which are not in the crates/ra_syntax/test_data folder | 130 | !entry.path().components().any(|component| component.as_os_str() == "test_data") |
132 | component == Component::Normal(OsStr::new("test_data")) | ||
133 | }) | ||
134 | }) | 131 | }) |
135 | .map(|e| e.unwrap()) | 132 | .map(|e| e.unwrap()) |
136 | .filter(|entry| { | 133 | .filter(|entry| { |
137 | // Get all `.rs ` files | 134 | // Get all `.rs ` files |
138 | !entry.path().is_dir() && (entry.path().extension() == Some(OsStr::new("rs"))) | 135 | !entry.path().is_dir() && (entry.path().extension().unwrap_or_default() == "rs") |
139 | }) | 136 | }) |
140 | { | 137 | .map(|entry| entry.into_path()) |
141 | count += 1; | 138 | .collect::<Vec<_>>(); |
142 | let text = read_text(entry.path()); | ||
143 | if let Err(errors) = SourceFile::parse(&text).ok() { | ||
144 | panic!("Parsing errors:\n{:?}\n{}\n", errors, entry.path().display()); | ||
145 | } | ||
146 | } | ||
147 | assert!( | 139 | assert!( |
148 | count > 30, | 140 | files.len() > 100, |
149 | "self_hosting_parsing found too few files - is it running in the right directory?" | 141 | "self_hosting_parsing found too few files - is it running in the right directory?" |
150 | ) | 142 | ); |
143 | |||
144 | let errors = files | ||
145 | .into_par_iter() | ||
146 | .filter_map(|file| { | ||
147 | let text = read_text(&file); | ||
148 | match SourceFile::parse(&text).ok() { | ||
149 | Ok(_) => None, | ||
150 | Err(err) => Some((file, err)), | ||
151 | } | ||
152 | }) | ||
153 | .collect::<Vec<_>>(); | ||
154 | |||
155 | if !errors.is_empty() { | ||
156 | let errors = errors | ||
157 | .into_iter() | ||
158 | .map(|(path, err)| format!("{}: {:?}\n", path.display(), err)) | ||
159 | .collect::<String>(); | ||
160 | panic!("Parsing errors:\n{}\n", errors); | ||
161 | } | ||
151 | } | 162 | } |
152 | 163 | ||
153 | fn test_data_dir() -> PathBuf { | 164 | fn test_data_dir() -> PathBuf { |
@@ -218,15 +229,7 @@ where | |||
218 | for (path, input_code) in collect_rust_files(test_data_dir, paths) { | 229 | for (path, input_code) in collect_rust_files(test_data_dir, paths) { |
219 | let actual = f(&input_code, &path); | 230 | let actual = f(&input_code, &path); |
220 | let path = path.with_extension(outfile_extension); | 231 | let path = path.with_extension(outfile_extension); |
221 | if !path.exists() { | 232 | expect_file![path].assert_eq(&actual) |
222 | println!("\nfile: {}", path.display()); | ||
223 | println!("No .txt file with expected result, creating...\n"); | ||
224 | println!("{}\n{}", input_code, actual); | ||
225 | fs::write(&path, &actual).unwrap(); | ||
226 | panic!("No expected result"); | ||
227 | } | ||
228 | let expected = read_text(&path); | ||
229 | assert_equal_text(&expected, &actual, &path); | ||
230 | } | 233 | } |
231 | } | 234 | } |
232 | 235 | ||
@@ -259,29 +262,6 @@ fn rust_files_in_dir(dir: &Path) -> Vec<PathBuf> { | |||
259 | acc | 262 | acc |
260 | } | 263 | } |
261 | 264 | ||
262 | /// Asserts that `expected` and `actual` strings are equal. If they differ only | ||
263 | /// in trailing or leading whitespace the test won't fail and | ||
264 | /// the contents of `actual` will be written to the file located at `path`. | ||
265 | fn assert_equal_text(expected: &str, actual: &str, path: &Path) { | ||
266 | if expected == actual { | ||
267 | return; | ||
268 | } | ||
269 | let dir = project_dir(); | ||
270 | let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path); | ||
271 | if expected.trim() == actual.trim() { | ||
272 | println!("whitespace difference, rewriting"); | ||
273 | println!("file: {}\n", pretty_path.display()); | ||
274 | fs::write(path, actual).unwrap(); | ||
275 | return; | ||
276 | } | ||
277 | if env::var("UPDATE_EXPECT").is_ok() { | ||
278 | println!("rewriting {}", pretty_path.display()); | ||
279 | fs::write(path, actual).unwrap(); | ||
280 | return; | ||
281 | } | ||
282 | assert_eq_text!(expected, actual, "file: {}", pretty_path.display()); | ||
283 | } | ||
284 | |||
285 | /// Read file and normalize newlines. | 265 | /// Read file and normalize newlines. |
286 | /// | 266 | /// |
287 | /// `rustc` seems to always normalize `\r\n` newlines to `\n`: | 267 | /// `rustc` seems to always normalize `\r\n` newlines to `\n`: |