aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir_def/src/body/lower.rs16
-rw-r--r--crates/hir_def/src/expr.rs16
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/infer/expr.rs2
-rw-r--r--crates/hir_ty/src/infer/pat.rs6
-rw-r--r--crates/hir_ty/src/tests/patterns.rs30
-rw-r--r--crates/hir_ty/src/tests/simple.rs13
-rw-r--r--crates/hir_ty/src/traits/chalk.rs11
-rw-r--r--crates/ide/src/diagnostics.rs13
-rw-r--r--crates/ide/src/lib.rs8
-rw-r--r--crates/ide/src/references/rename.rs19
-rw-r--r--crates/rust-analyzer/Cargo.toml1
-rw-r--r--crates/rust-analyzer/src/caps.rs29
-rw-r--r--crates/rust-analyzer/src/handlers.rs158
-rw-r--r--crates/rust-analyzer/src/lib.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/expr_ext.rs4
19 files changed, 256 insertions, 87 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 1d7e5ddd7..6d17d546a 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -374,8 +374,6 @@ impl Module {
374 let crate_def_map = db.crate_def_map(self.id.krate); 374 let crate_def_map = db.crate_def_map(self.id.krate);
375 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 375 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
376 for decl in self.declarations(db) { 376 for decl in self.declarations(db) {
377 decl.diagnostics(db, sink);
378
379 match decl { 377 match decl {
380 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 378 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
381 crate::ModuleDef::Module(m) => { 379 crate::ModuleDef::Module(m) => {
@@ -384,7 +382,9 @@ impl Module {
384 m.diagnostics(db, sink) 382 m.diagnostics(db, sink)
385 } 383 }
386 } 384 }
387 _ => (), 385 _ => {
386 decl.diagnostics(db, sink);
387 }
388 } 388 }
389 } 389 }
390 390
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 978c3a324..1b98504bb 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -246,6 +246,10 @@ impl ExprCollector<'_> {
246 let body = self.collect_block_opt(e.block_expr()); 246 let body = self.collect_block_opt(e.block_expr());
247 self.alloc_expr(Expr::Async { body }, syntax_ptr) 247 self.alloc_expr(Expr::Async { body }, syntax_ptr)
248 } 248 }
249 ast::Effect::Const(_) => {
250 let body = self.collect_block_opt(e.block_expr());
251 self.alloc_expr(Expr::Const { body }, syntax_ptr)
252 }
249 }, 253 },
250 ast::Expr::BlockExpr(e) => self.collect_block(e), 254 ast::Expr::BlockExpr(e) => self.collect_block(e),
251 ast::Expr::LoopExpr(e) => { 255 ast::Expr::LoopExpr(e) => {
@@ -932,10 +936,16 @@ impl ExprCollector<'_> {
932 let inner = self.collect_pat_opt(boxpat.pat()); 936 let inner = self.collect_pat_opt(boxpat.pat());
933 Pat::Box { inner } 937 Pat::Box { inner }
934 } 938 }
935 // FIXME: implement 939 ast::Pat::ConstBlockPat(const_block_pat) => {
936 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) | ast::Pat::ConstBlockPat(_) => { 940 if let Some(expr) = const_block_pat.block_expr() {
937 Pat::Missing 941 let expr_id = self.collect_block(expr);
942 Pat::ConstBlock(expr_id)
943 } else {
944 Pat::Missing
945 }
938 } 946 }
947 // FIXME: implement
948 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
939 }; 949 };
940 let ptr = AstPtr::new(&pat); 950 let ptr = AstPtr::new(&pat);
941 self.alloc_pat(pattern, Either::Left(ptr)) 951 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index e5d740a36..3bba30397 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -114,6 +114,9 @@ pub enum Expr {
114 Async { 114 Async {
115 body: ExprId, 115 body: ExprId,
116 }, 116 },
117 Const {
118 body: ExprId,
119 },
117 Cast { 120 Cast {
118 expr: ExprId, 121 expr: ExprId,
119 type_ref: TypeRef, 122 type_ref: TypeRef,
@@ -253,7 +256,10 @@ impl Expr {
253 f(*expr); 256 f(*expr);
254 } 257 }
255 } 258 }
256 Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body), 259 Expr::TryBlock { body }
260 | Expr::Unsafe { body }
261 | Expr::Async { body }
262 | Expr::Const { body } => f(*body),
257 Expr::Loop { body, .. } => f(*body), 263 Expr::Loop { body, .. } => f(*body),
258 Expr::While { condition, body, .. } => { 264 Expr::While { condition, body, .. } => {
259 f(*condition); 265 f(*condition);
@@ -399,12 +405,18 @@ pub enum Pat {
399 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, 405 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> },
400 Ref { pat: PatId, mutability: Mutability }, 406 Ref { pat: PatId, mutability: Mutability },
401 Box { inner: PatId }, 407 Box { inner: PatId },
408 ConstBlock(ExprId),
402} 409}
403 410
404impl Pat { 411impl Pat {
405 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { 412 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
406 match self { 413 match self {
407 Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} 414 Pat::Range { .. }
415 | Pat::Lit(..)
416 | Pat::Path(..)
417 | Pat::ConstBlock(..)
418 | Pat::Wild
419 | Pat::Missing => {}
408 Pat::Bind { subpat, .. } => { 420 Pat::Bind { subpat, .. } => {
409 subpat.iter().copied().for_each(f); 421 subpat.iter().copied().for_each(f);
410 } 422 }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 289e812fe..965c1780a 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.43", default-features = false } 20chalk-solve = { version = "0.45", default-features = false }
21chalk-ir = "0.43" 21chalk-ir = "0.45"
22chalk-recursive = "0.43" 22chalk-recursive = "0.45"
23 23
24stdx = { path = "../stdx", version = "0.0.0" } 24stdx = { path = "../stdx", version = "0.0.0" }
25hir_def = { path = "../hir_def", version = "0.0.0" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 2cdce2cef..744569e6e 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> {
155 } 155 }
156 None => self.infer_block(statements, *tail, expected), 156 None => self.infer_block(statements, *tail, expected),
157 }, 157 },
158 Expr::Unsafe { body } => self.infer_expr(*body, expected), 158 Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
159 Expr::TryBlock { body } => { 159 Expr::TryBlock { body } => {
160 let _inner = self.infer_expr(*body, expected); 160 let _inner = self.infer_expr(*body, expected);
161 // FIXME should be std::result::Result<{inner}, _> 161 // FIXME should be std::result::Result<{inner}, _>
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index b70ec55eb..d974f805b 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -243,6 +243,9 @@ impl<'a> InferenceContext<'a> {
243 } 243 }
244 None => Ty::Unknown, 244 None => Ty::Unknown,
245 }, 245 },
246 Pat::ConstBlock(expr) => {
247 self.infer_expr(*expr, &Expectation::has_type(expected.clone()))
248 }
246 Pat::Missing => Ty::Unknown, 249 Pat::Missing => Ty::Unknown,
247 }; 250 };
248 // use a new type variable if we got Ty::Unknown here 251 // use a new type variable if we got Ty::Unknown here
@@ -264,8 +267,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
264 | Pat::Range { .. } 267 | Pat::Range { .. }
265 | Pat::Slice { .. } => true, 268 | Pat::Slice { .. } => true,
266 Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), 269 Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
267 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. 270 // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
268 Pat::Path(..) => true, 271 Pat::Path(..) => true,
272 Pat::ConstBlock(..) => true,
269 Pat::Lit(expr) => match body[*expr] { 273 Pat::Lit(expr) => match body[*expr] {
270 Expr::Literal(Literal::String(..)) => false, 274 Expr::Literal(Literal::String(..)) => false,
271 _ => true, 275 _ => true,
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 5a5f48fd0..2053d8f56 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -774,3 +774,33 @@ fn foo(tuple: Tuple) {
774 "#]], 774 "#]],
775 ); 775 );
776} 776}
777
778#[test]
779fn const_block_pattern() {
780 check_infer(
781 r#"
782struct Foo(usize);
783fn foo(foo: Foo) {
784 match foo {
785 const { Foo(15 + 32) } => {},
786 _ => {}
787 }
788}"#,
789 expect![[r#"
790 26..29 'foo': Foo
791 36..115 '{ ... } }': ()
792 42..113 'match ... }': ()
793 48..51 'foo': Foo
794 62..84 'const ... 32) }': Foo
795 68..84 '{ Foo(... 32) }': Foo
796 70..73 'Foo': Foo(usize) -> Foo
797 70..82 'Foo(15 + 32)': Foo
798 74..76 '15': usize
799 74..81 '15 + 32': usize
800 79..81 '32': usize
801 88..90 '{}': ()
802 100..101 '_': Foo
803 105..107 '{}': ()
804 "#]],
805 );
806}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index a569223b4..a61282d5a 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1894,6 +1894,7 @@ fn effects_smoke_test() {
1894 let x = unsafe { 92 }; 1894 let x = unsafe { 92 };
1895 let y = async { async { () }.await }; 1895 let y = async { async { () }.await };
1896 let z = try { () }; 1896 let z = try { () };
1897 let w = const { 92 };
1897 let t = 'a: { 92 }; 1898 let t = 'a: { 92 };
1898 } 1899 }
1899 1900
@@ -1905,7 +1906,7 @@ fn effects_smoke_test() {
1905 } 1906 }
1906 "#, 1907 "#,
1907 expect![[r#" 1908 expect![[r#"
1908 16..136 '{ ...2 }; }': () 1909 16..162 '{ ...2 }; }': ()
1909 26..27 'x': i32 1910 26..27 'x': i32
1910 30..43 'unsafe { 92 }': i32 1911 30..43 'unsafe { 92 }': i32
1911 37..43 '{ 92 }': i32 1912 37..43 '{ 92 }': i32
@@ -1921,9 +1922,13 @@ fn effects_smoke_test() {
1921 99..109 'try { () }': {unknown} 1922 99..109 'try { () }': {unknown}
1922 103..109 '{ () }': () 1923 103..109 '{ () }': ()
1923 105..107 '()': () 1924 105..107 '()': ()
1924 119..120 't': i32 1925 119..120 'w': i32
1925 127..133 '{ 92 }': i32 1926 123..135 'const { 92 }': i32
1926 129..131 '92': i32 1927 129..135 '{ 92 }': i32
1928 131..133 '92': i32
1929 145..146 't': i32
1930 153..159 '{ 92 }': i32
1931 155..157 '92': i32
1927 "#]], 1932 "#]],
1928 ) 1933 )
1929} 1934}
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 69eae6f79..2196af677 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -56,8 +56,13 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
56 fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> { 56 fn adt_datum(&self, struct_id: AdtId) -> Arc<StructDatum> {
57 self.db.struct_datum(self.krate, struct_id) 57 self.db.struct_datum(self.krate, struct_id)
58 } 58 }
59 fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr { 59 fn adt_repr(&self, _struct_id: AdtId) -> Arc<rust_ir::AdtRepr<Interner>> {
60 rust_ir::AdtRepr { repr_c: false, repr_packed: false } 60 // FIXME: keep track of these
61 Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None })
62 }
63 fn discriminant_type(&self, _ty: chalk_ir::Ty<Interner>) -> chalk_ir::Ty<Interner> {
64 // FIXME: keep track of this
65 chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(&Interner)
61 } 66 }
62 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { 67 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
63 self.db.impl_datum(self.krate, impl_id) 68 self.db.impl_datum(self.krate, impl_id)
@@ -457,6 +462,7 @@ fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
457 "fn" => WellKnownTrait::Fn, 462 "fn" => WellKnownTrait::Fn,
458 "unsize" => WellKnownTrait::Unsize, 463 "unsize" => WellKnownTrait::Unsize,
459 "coerce_unsized" => WellKnownTrait::CoerceUnsized, 464 "coerce_unsized" => WellKnownTrait::CoerceUnsized,
465 "discriminant_kind" => WellKnownTrait::DiscriminantKind,
460 _ => return None, 466 _ => return None,
461 }) 467 })
462} 468}
@@ -473,6 +479,7 @@ fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
473 WellKnownTrait::Unsize => "unsize", 479 WellKnownTrait::Unsize => "unsize",
474 WellKnownTrait::Unpin => "unpin", 480 WellKnownTrait::Unpin => "unpin",
475 WellKnownTrait::CoerceUnsized => "coerce_unsized", 481 WellKnownTrait::CoerceUnsized => "coerce_unsized",
482 WellKnownTrait::DiscriminantKind => "discriminant_kind",
476 } 483 }
477} 484}
478 485
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 3ad30f0c9..b2714cb69 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -895,4 +895,17 @@ impl TestStruct {
895"#, 895"#,
896 ); 896 );
897 } 897 }
898
899 #[test]
900 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
901 let input = r#"fn FOO<|>() {}"#;
902 let expected = r#"fn foo() {}"#;
903
904 let (analysis, file_position) = fixture::position(input);
905 let diagnostics =
906 analysis.diagnostics(&DiagnosticsConfig::default(), file_position.file_id).unwrap();
907 assert_eq!(diagnostics.len(), 1);
908
909 check_fixes(input, expected);
910 }
898} 911}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index dbad9a84f..52c7f9775 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -535,6 +535,14 @@ impl Analysis {
535 self.with_db(|db| references::rename::prepare_rename(db, position)) 535 self.with_db(|db| references::rename::prepare_rename(db, position))
536 } 536 }
537 537
538 pub fn will_rename_file(
539 &self,
540 file_id: FileId,
541 new_name_stem: &str,
542 ) -> Cancelable<Option<SourceChange>> {
543 self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem))
544 }
545
538 pub fn structural_search_replace( 546 pub fn structural_search_replace(
539 &self, 547 &self,
540 query: &str, 548 query: &str,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index cd721b7eb..15c95f239 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -6,7 +6,7 @@ use std::{
6}; 6};
7 7
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 8use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileRange, SourceDatabaseExt}; 9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 10use ide_db::{
11 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
12 RootDatabase, 12 RootDatabase,
@@ -110,6 +110,23 @@ pub(crate) fn rename_with_semantics(
110 } 110 }
111} 111}
112 112
113pub(crate) fn will_rename_file(
114 db: &RootDatabase,
115 file_id: FileId,
116 new_name_stem: &str,
117) -> Option<SourceChange> {
118 let sema = Semantics::new(db);
119 let module = sema.to_module_def(file_id)?;
120
121 let decl = module.declaration_source(db)?;
122 let range = decl.value.name()?.syntax().text_range();
123
124 let position = FilePosition { file_id: decl.file_id.original_file(db), offset: range.start() };
125 let mut change = rename_mod(&sema, position, module, new_name_stem).ok()?.info;
126 change.file_system_edits.clear();
127 Some(change)
128}
129
113fn find_module_at_offset( 130fn find_module_at_offset(
114 sema: &Semantics<RootDatabase>, 131 sema: &Semantics<RootDatabase>,
115 position: FilePosition, 132 position: FilePosition,
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 0b4d3f4eb..53e70eaf7 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -28,6 +28,7 @@ oorandom = "11.1.2"
28rustc-hash = "1.1.0" 28rustc-hash = "1.1.0"
29serde = { version = "1.0.106", features = ["derive"] } 29serde = { version = "1.0.106", features = ["derive"] }
30serde_json = { version = "1.0.48", features = ["preserve_order"] } 30serde_json = { version = "1.0.48", features = ["preserve_order"] }
31serde_path_to_error = "0.1"
31threadpool = "1.7.1" 32threadpool = "1.7.1"
32rayon = "1.5" 33rayon = "1.5"
33mimalloc = { version = "0.1.19", default-features = false, optional = true } 34mimalloc = { version = "0.1.19", default-features = false, optional = true }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index de5eb93b5..80e46bf7f 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -5,12 +5,14 @@ use ide::CompletionResolveCapability;
5use lsp_types::{ 5use lsp_types::{
6 CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, 6 CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
7 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, 7 CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
8 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability, 8 DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationPattern,
9 ImplementationProviderCapability, OneOf, RenameOptions, SaveOptions, 9 FileOperationPatternKind, FileOperationRegistrationOptions, FoldingRangeProviderCapability,
10 HoverProviderCapability, ImplementationProviderCapability, OneOf, RenameOptions, SaveOptions,
10 SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend, 11 SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend,
11 SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, 12 SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability,
12 TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, 13 TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability,
13 WorkDoneProgressOptions, 14 WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities,
15 WorkspaceServerCapabilities,
14}; 16};
15use rustc_hash::FxHashSet; 17use rustc_hash::FxHashSet;
16use serde_json::json; 18use serde_json::json;
@@ -68,7 +70,26 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
68 document_link_provider: None, 70 document_link_provider: None,
69 color_provider: None, 71 color_provider: None,
70 execute_command_provider: None, 72 execute_command_provider: None,
71 workspace: None, 73 workspace: Some(WorkspaceServerCapabilities {
74 workspace_folders: None,
75 file_operations: Some(WorkspaceFileOperationsServerCapabilities {
76 did_create: None,
77 will_create: None,
78 did_rename: None,
79 will_rename: Some(FileOperationRegistrationOptions {
80 filters: vec![FileOperationFilter {
81 scheme: Some(String::from("file")),
82 pattern: FileOperationPattern {
83 glob: String::from("**/*.rs"),
84 matches: Some(FileOperationPatternKind::File),
85 options: None,
86 },
87 }],
88 }),
89 did_delete: None,
90 will_delete: None,
91 }),
92 }),
72 call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), 93 call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
73 semantic_tokens_provider: Some( 94 semantic_tokens_provider: Some(
74 SemanticTokensOptions { 95 SemanticTokensOptions {
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 66f8bee99..25692793b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -5,11 +5,13 @@
5use std::{ 5use std::{
6 io::Write as _, 6 io::Write as _,
7 process::{self, Stdio}, 7 process::{self, Stdio},
8 sync::Arc,
8}; 9};
9 10
10use ide::{ 11use ide::{
11 CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, 12 AssistConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction,
12 NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SymbolKind, TextEdit, 13 HoverGotoTypeData, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind,
14 SearchScope, SourceChange, SymbolKind, TextEdit,
13}; 15};
14use itertools::Itertools; 16use itertools::Itertools;
15use lsp_server::ErrorCode; 17use lsp_server::ErrorCode;
@@ -400,6 +402,45 @@ pub(crate) fn handle_workspace_symbol(
400 } 402 }
401} 403}
402 404
405pub(crate) fn handle_will_rename_files(
406 snap: GlobalStateSnapshot,
407 params: lsp_types::RenameFilesParams,
408) -> Result<Option<lsp_types::WorkspaceEdit>> {
409 let _p = profile::span("handle_will_rename_files");
410
411 let source_changes: Vec<SourceChange> = params
412 .files
413 .into_iter()
414 .filter_map(|file_rename| {
415 let from = Url::parse(&file_rename.old_uri).ok()?;
416 let to = Url::parse(&file_rename.new_uri).ok()?;
417
418 let from_path = from.to_file_path().ok()?;
419 let to_path = to.to_file_path().ok()?;
420
421 // Limit to single-level moves for now.
422 match (from_path.parent(), to_path.parent()) {
423 (Some(p1), Some(p2)) if p1 == p2 => {
424 let new_name = to_path.file_stem()?;
425 let new_name = new_name.to_str()?;
426 Some((snap.url_to_file_id(&from).ok()?, new_name.to_string()))
427 }
428 _ => None,
429 }
430 })
431 .filter_map(|(file_id, new_name)| {
432 snap.analysis.will_rename_file(file_id, &new_name).ok()?
433 })
434 .collect();
435
436 // Drop file system edits since we're just renaming things on the same level
437 let edits = source_changes.into_iter().map(|it| it.source_file_edits).flatten().collect();
438 let source_change = SourceChange::from_edits(edits, Vec::new());
439
440 let workspace_edit = to_proto::workspace_edit(&snap, source_change)?;
441 Ok(Some(workspace_edit))
442}
443
403pub(crate) fn handle_goto_definition( 444pub(crate) fn handle_goto_definition(
404 snap: GlobalStateSnapshot, 445 snap: GlobalStateSnapshot,
405 params: lsp_types::GotoDefinitionParams, 446 params: lsp_types::GotoDefinitionParams,
@@ -865,58 +906,8 @@ pub(crate) fn handle_formatting(
865 } 906 }
866} 907}
867 908
868fn handle_fixes(
869 snap: &GlobalStateSnapshot,
870 params: &lsp_types::CodeActionParams,
871 res: &mut Vec<lsp_ext::CodeAction>,
872) -> Result<()> {
873 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
874 let line_index = snap.analysis.file_line_index(file_id)?;
875 let range = from_proto::text_range(&line_index, params.range);
876
877 match &params.context.only {
878 Some(v) => {
879 if !v.iter().any(|it| {
880 it == &lsp_types::CodeActionKind::EMPTY
881 || it == &lsp_types::CodeActionKind::QUICKFIX
882 }) {
883 return Ok(());
884 }
885 }
886 None => {}
887 };
888
889 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, file_id)?;
890
891 for fix in diagnostics
892 .into_iter()
893 .filter_map(|d| d.fix)
894 .filter(|fix| fix.fix_trigger_range.intersect(range).is_some())
895 {
896 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
897 let action = lsp_ext::CodeAction {
898 title: fix.label.to_string(),
899 group: None,
900 kind: Some(CodeActionKind::QUICKFIX),
901 edit: Some(edit),
902 is_preferred: Some(false),
903 data: None,
904 };
905 res.push(action);
906 }
907
908 for fix in snap.check_fixes.get(&file_id).into_iter().flatten() {
909 let fix_range = from_proto::text_range(&line_index, fix.range);
910 if fix_range.intersect(range).is_none() {
911 continue;
912 }
913 res.push(fix.action.clone());
914 }
915 Ok(())
916}
917
918pub(crate) fn handle_code_action( 909pub(crate) fn handle_code_action(
919 mut snap: GlobalStateSnapshot, 910 snap: GlobalStateSnapshot,
920 params: lsp_types::CodeActionParams, 911 params: lsp_types::CodeActionParams,
921) -> Result<Option<Vec<lsp_ext::CodeAction>>> { 912) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
922 let _p = profile::span("handle_code_action"); 913 let _p = profile::span("handle_code_action");
@@ -932,24 +923,35 @@ pub(crate) fn handle_code_action(
932 let range = from_proto::text_range(&line_index, params.range); 923 let range = from_proto::text_range(&line_index, params.range);
933 let frange = FileRange { file_id, range }; 924 let frange = FileRange { file_id, range };
934 925
935 snap.config.assist.allowed = params 926 let assists_config = AssistConfig {
936 .clone() 927 allowed: params
937 .context 928 .clone()
938 .only 929 .context
939 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); 930 .only
931 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()),
932 ..snap.config.assist
933 };
940 934
941 let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); 935 let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
942 936
943 handle_fixes(&snap, &params, &mut res)?; 937 let include_quick_fixes = match &params.context.only {
938 Some(v) => v.iter().any(|it| {
939 it == &lsp_types::CodeActionKind::EMPTY || it == &lsp_types::CodeActionKind::QUICKFIX
940 }),
941 None => true,
942 };
943 if include_quick_fixes {
944 add_quick_fixes(&snap, frange, &line_index, &mut res)?;
945 }
944 946
945 if snap.config.client_caps.code_action_resolve { 947 if snap.config.client_caps.code_action_resolve {
946 for (index, assist) in 948 for (index, assist) in
947 snap.analysis.unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() 949 snap.analysis.unresolved_assists(&assists_config, frange)?.into_iter().enumerate()
948 { 950 {
949 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?); 951 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?);
950 } 952 }
951 } else { 953 } else {
952 for assist in snap.analysis.resolved_assists(&snap.config.assist, frange)?.into_iter() { 954 for assist in snap.analysis.resolved_assists(&assists_config, frange)?.into_iter() {
953 res.push(to_proto::resolved_code_action(&snap, assist)?); 955 res.push(to_proto::resolved_code_action(&snap, assist)?);
954 } 956 }
955 } 957 }
@@ -957,6 +959,40 @@ pub(crate) fn handle_code_action(
957 Ok(Some(res)) 959 Ok(Some(res))
958} 960}
959 961
962fn add_quick_fixes(
963 snap: &GlobalStateSnapshot,
964 frange: FileRange,
965 line_index: &Arc<LineIndex>,
966 acc: &mut Vec<lsp_ext::CodeAction>,
967) -> Result<()> {
968 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, frange.file_id)?;
969
970 for fix in diagnostics
971 .into_iter()
972 .filter_map(|d| d.fix)
973 .filter(|fix| fix.fix_trigger_range.intersect(frange.range).is_some())
974 {
975 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
976 let action = lsp_ext::CodeAction {
977 title: fix.label.to_string(),
978 group: None,
979 kind: Some(CodeActionKind::QUICKFIX),
980 edit: Some(edit),
981 is_preferred: Some(false),
982 data: None,
983 };
984 acc.push(action);
985 }
986
987 for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
988 let fix_range = from_proto::text_range(&line_index, fix.range);
989 if fix_range.intersect(frange.range).is_some() {
990 acc.push(fix.action.clone());
991 }
992 }
993 Ok(())
994}
995
960pub(crate) fn handle_code_action_resolve( 996pub(crate) fn handle_code_action_resolve(
961 mut snap: GlobalStateSnapshot, 997 mut snap: GlobalStateSnapshot,
962 mut code_action: lsp_ext::CodeAction, 998 mut code_action: lsp_ext::CodeAction,
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 79fe30e53..d538ad69a 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -46,7 +46,7 @@ pub type Error = Box<dyn std::error::Error + Send + Sync>;
46pub type Result<T, E = Error> = std::result::Result<T, E>; 46pub type Result<T, E = Error> = std::result::Result<T, E>;
47 47
48pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { 48pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
49 let res = T::deserialize(&json) 49 let res = serde_path_to_error::deserialize(&json)
50 .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; 50 .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?;
51 Ok(res) 51 Ok(res)
52} 52}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ec3d5e060..5d55dc96e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -485,6 +485,7 @@ impl GlobalState {
485 .on::<lsp_types::request::SemanticTokensRangeRequest>( 485 .on::<lsp_types::request::SemanticTokensRangeRequest>(
486 handlers::handle_semantic_tokens_range, 486 handlers::handle_semantic_tokens_range,
487 ) 487 )
488 .on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
488 .on::<lsp_ext::Ssr>(handlers::handle_ssr) 489 .on::<lsp_ext::Ssr>(handlers::handle_ssr)
489 .finish(); 490 .finish();
490 Ok(()) 491 Ok(())
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index c6a6f11e1..21015591c 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "691.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index e4a9b945c..636ce166d 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -358,6 +358,7 @@ pub enum Effect {
358 Async(SyntaxToken), 358 Async(SyntaxToken),
359 Unsafe(SyntaxToken), 359 Unsafe(SyntaxToken),
360 Try(SyntaxToken), 360 Try(SyntaxToken),
361 Const(SyntaxToken),
361 // Very much not an effect, but we stuff it into this node anyway 362 // Very much not an effect, but we stuff it into this node anyway
362 Label(ast::Label), 363 Label(ast::Label),
363} 364}
@@ -373,6 +374,9 @@ impl ast::EffectExpr {
373 if let Some(token) = self.try_token() { 374 if let Some(token) = self.try_token() {
374 return Effect::Try(token); 375 return Effect::Try(token);
375 } 376 }
377 if let Some(token) = self.const_token() {
378 return Effect::Const(token);
379 }
376 if let Some(label) = self.label() { 380 if let Some(label) = self.label() {
377 return Effect::Label(label); 381 return Effect::Label(label);
378 } 382 }