aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/invert_if.rs13
-rw-r--r--crates/ra_hir_expand/src/db.rs24
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs31
-rw-r--r--crates/ra_project_model/src/lib.rs6
-rw-r--r--crates/ra_syntax/src/algo.rs4
-rw-r--r--editors/code/src/inlay_hints.ts2
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs10
-rw-r--r--xtask/src/lib.rs16
-rw-r--r--xtask/tests/tidy-tests/main.rs21
9 files changed, 93 insertions, 34 deletions
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs
index 3a2665d17..4c5716868 100644
--- a/crates/ra_assists/src/handlers/invert_if.rs
+++ b/crates/ra_assists/src/handlers/invert_if.rs
@@ -33,6 +33,11 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
33 return None; 33 return None;
34 } 34 }
35 35
36 // This assist should not apply for if-let.
37 if expr.condition()?.pat().is_some() {
38 return None;
39 }
40
36 let cond = expr.condition()?.expr()?; 41 let cond = expr.condition()?.expr()?;
37 let then_node = expr.then_branch()?.syntax().clone(); 42 let then_node = expr.then_branch()?.syntax().clone();
38 43
@@ -90,4 +95,12 @@ mod tests {
90 fn invert_if_doesnt_apply_with_cursor_not_on_if() { 95 fn invert_if_doesnt_apply_with_cursor_not_on_if() {
91 check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }") 96 check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
92 } 97 }
98
99 #[test]
100 fn invert_if_doesnt_apply_with_if_let() {
101 check_assist_not_applicable(
102 invert_if,
103 "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }",
104 )
105 }
93} 106}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index d171d2dfd..5a696542f 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,7 +6,7 @@ use mbe::{ExpandResult, MacroRules};
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode}; 9use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
@@ -238,7 +238,7 @@ pub fn parse_macro_with_arg(
238 } else { 238 } else {
239 db.macro_expand(macro_call_id) 239 db.macro_expand(macro_call_id)
240 }; 240 };
241 if let Some(err) = err { 241 if let Some(err) = &err {
242 // Note: 242 // Note:
243 // The final goal we would like to make all parse_macro success, 243 // The final goal we would like to make all parse_macro success,
244 // such that the following log will not call anyway. 244 // such that the following log will not call anyway.
@@ -272,7 +272,25 @@ pub fn parse_macro_with_arg(
272 let fragment_kind = to_fragment_kind(db, macro_call_id); 272 let fragment_kind = to_fragment_kind(db, macro_call_id);
273 273
274 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; 274 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
275 Some((parse, Arc::new(rev_token_map))) 275
276 if err.is_none() {
277 Some((parse, Arc::new(rev_token_map)))
278 } else {
279 // FIXME:
280 // In future, we should propagate the actual error with recovery information
281 // instead of ignore the error here.
282
283 // Safe check for recurisve identity macro
284 let node = parse.syntax_node();
285 let file: HirFileId = macro_file.into();
286 let call_node = file.call_node(db)?;
287
288 if !diff(&node, &call_node.value).is_empty() {
289 Some((parse, Arc::new(rev_token_map)))
290 } else {
291 None
292 }
293 }
276} 294}
277 295
278/// Given a `MacroCallId`, return what `FragmentKind` it belongs to. 296/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 14c8ed3a9..a02e3ee05 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -453,3 +453,34 @@ pub mod str {
453 // should be Option<char>, but currently not because of Chalk ambiguity problem 453 // should be Option<char>, but currently not because of Chalk ambiguity problem
454 assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos)); 454 assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos));
455} 455}
456
457#[test]
458fn issue_3642_bad_macro_stackover() {
459 let (db, pos) = TestDB::with_position(
460 r#"
461//- /main.rs
462#[macro_export]
463macro_rules! match_ast {
464 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
465
466 (match ($node:expr) {
467 $( ast::$ast:ident($it:ident) => $res:expr, )*
468 _ => $catch_all:expr $(,)?
469 }) => {{
470 $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
471 { $catch_all }
472 }};
473}
474
475fn main() {
476 let anchor<|> = match_ast! {
477 match parent {
478 as => {},
479 _ => return None
480 }
481 };
482}"#,
483 );
484
485 assert_eq!("()", super::type_at_pos(&db, pos));
486}
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index b500a74fb..a3ef9acdc 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -336,7 +336,7 @@ impl ProjectWorkspace {
336 extern_source, 336 extern_source,
337 ); 337 );
338 if cargo[tgt].kind == TargetKind::Lib { 338 if cargo[tgt].kind == TargetKind::Lib {
339 lib_tgt = Some(crate_id); 339 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
340 pkg_to_lib_crate.insert(pkg, crate_id); 340 pkg_to_lib_crate.insert(pkg, crate_id);
341 } 341 }
342 if cargo[tgt].is_proc_macro { 342 if cargo[tgt].is_proc_macro {
@@ -363,7 +363,7 @@ impl ProjectWorkspace {
363 363
364 // Set deps to the core, std and to the lib target of the current package 364 // Set deps to the core, std and to the lib target of the current package
365 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 365 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
366 if let Some(to) = lib_tgt { 366 if let Some((to, name)) = lib_tgt.clone() {
367 if to != from 367 if to != from
368 && crate_graph 368 && crate_graph
369 .add_dep( 369 .add_dep(
@@ -371,7 +371,7 @@ impl ProjectWorkspace {
371 // For root projects with dashes in their name, 371 // For root projects with dashes in their name,
372 // cargo metadata does not do any normalization, 372 // cargo metadata does not do any normalization,
373 // so we do it ourselves currently 373 // so we do it ourselves currently
374 CrateName::normalize_dashes(&cargo[pkg].name), 374 CrateName::normalize_dashes(&name),
375 to, 375 to,
376 ) 376 )
377 .is_err() 377 .is_err()
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 344cf0fbe..ffdbdc767 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -95,6 +95,10 @@ impl TreeDiff {
95 builder.replace(from.text_range(), to.to_string()) 95 builder.replace(from.text_range(), to.to_string())
96 } 96 }
97 } 97 }
98
99 pub fn is_empty(&self) -> bool {
100 self.replacements.is_empty()
101 }
98} 102}
99 103
100/// Finds minimal the diff, which, applied to `from`, will result in `to`. 104/// Finds minimal the diff, which, applied to `from`, will result in `to`.
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index b19b09ad5..17d0dfa33 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -134,8 +134,6 @@ class HintsUpdater implements Disposable {
134 134
135 // No text documents changed, so we may try to use the cache 135 // No text documents changed, so we may try to use the cache
136 if (!file.cachedDecorations) { 136 if (!file.cachedDecorations) {
137 file.inlaysRequest?.cancel();
138
139 const hints = await this.fetchHints(file); 137 const hints = await this.fetchHints(file);
140 if (!hints) return; 138 if (!hints) return;
141 139
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 6da5ca89e..31d606535 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -4,7 +4,7 @@ use std::{fs, path::Path};
4 4
5use crate::{ 5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, 6 codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
7 project_root, Result, 7 project_root, rust_files, Result,
8}; 8};
9 9
10pub fn generate_assists_docs(mode: Mode) -> Result<()> { 10pub fn generate_assists_docs(mode: Mode) -> Result<()> {
@@ -46,12 +46,8 @@ fn reveal_hash_comments(text: &str) -> String {
46 46
47fn collect_assists() -> Result<Vec<Assist>> { 47fn collect_assists() -> Result<Vec<Assist>> {
48 let mut res = Vec::new(); 48 let mut res = Vec::new();
49 for entry in fs::read_dir(project_root().join(codegen::ASSISTS_DIR))? { 49 for path in rust_files(&project_root().join(codegen::ASSISTS_DIR)) {
50 let entry = entry?; 50 collect_file(&mut res, path.as_path())?;
51 let path = entry.path();
52 if path.is_file() {
53 collect_file(&mut res, path.as_path())?;
54 }
55 } 51 }
56 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); 52 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
57 return Ok(res); 53 return Ok(res);
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index e1472e85d..4f01f84fb 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -17,6 +17,7 @@ use std::{
17 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
18 process::{Command, Stdio}, 18 process::{Command, Stdio},
19}; 19};
20use walkdir::{DirEntry, WalkDir};
20 21
21use crate::{ 22use crate::{
22 codegen::Mode, 23 codegen::Mode,
@@ -37,6 +38,21 @@ pub fn project_root() -> PathBuf {
37 .to_path_buf() 38 .to_path_buf()
38} 39}
39 40
41pub fn rust_files(path: &Path) -> impl Iterator<Item = PathBuf> {
42 let iter = WalkDir::new(path);
43 return iter
44 .into_iter()
45 .filter_entry(|e| !is_hidden(e))
46 .map(|e| e.unwrap())
47 .filter(|e| !e.file_type().is_dir())
48 .map(|e| e.into_path())
49 .filter(|path| path.extension().map(|it| it == "rs").unwrap_or(false));
50
51 fn is_hidden(entry: &DirEntry) -> bool {
52 entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
53 }
54}
55
40pub fn run_rustfmt(mode: Mode) -> Result<()> { 56pub fn run_rustfmt(mode: Mode) -> Result<()> {
41 let _dir = pushd(project_root()); 57 let _dir = pushd(project_root());
42 ensure_rustfmt()?; 58 ensure_rustfmt()?;
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy-tests/main.rs
index 5ae86c87c..80911a68e 100644
--- a/xtask/tests/tidy-tests/main.rs
+++ b/xtask/tests/tidy-tests/main.rs
@@ -5,13 +5,12 @@ use std::{
5 path::{Path, PathBuf}, 5 path::{Path, PathBuf},
6}; 6};
7 7
8use walkdir::{DirEntry, WalkDir}; 8use xtask::{not_bash::fs2, project_root, rust_files};
9use xtask::{not_bash::fs2, project_root};
10 9
11#[test] 10#[test]
12fn rust_files_are_tidy() { 11fn rust_files_are_tidy() {
13 let mut tidy_docs = TidyDocs::default(); 12 let mut tidy_docs = TidyDocs::default();
14 for path in rust_files() { 13 for path in rust_files(&project_root().join("crates")) {
15 let text = fs2::read_to_string(&path).unwrap(); 14 let text = fs2::read_to_string(&path).unwrap();
16 check_todo(&path, &text); 15 check_todo(&path, &text);
17 check_trailing_ws(&path, &text); 16 check_trailing_ws(&path, &text);
@@ -142,19 +141,3 @@ fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
142 141
143 false 142 false
144} 143}
145
146fn rust_files() -> impl Iterator<Item = PathBuf> {
147 let crates = project_root().join("crates");
148 let iter = WalkDir::new(crates);
149 return iter
150 .into_iter()
151 .filter_entry(|e| !is_hidden(e))
152 .map(|e| e.unwrap())
153 .filter(|e| !e.file_type().is_dir())
154 .map(|e| e.into_path())
155 .filter(|path| path.extension().map(|it| it == "rs").unwrap_or(false));
156
157 fn is_hidden(entry: &DirEntry) -> bool {
158 entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
159 }
160}