aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml35
-rw-r--r--Cargo.lock12
-rw-r--r--crates/ide_assists/src/assist_context.rs39
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs33
-rw-r--r--crates/ide_assists/src/handlers/reorder_impl.rs40
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs22
-rw-r--r--crates/ide_completion/src/context.rs208
-rw-r--r--crates/proc_macro_api/Cargo.toml2
-rw-r--r--crates/proc_macro_api/src/version.rs2
-rw-r--r--docs/user/manual.adoc35
-rw-r--r--xtask/src/dist.rs1
-rw-r--r--xtask/src/flags.rs5
-rw-r--r--xtask/src/main.rs2
-rw-r--r--xtask/src/pre_cache.rs79
14 files changed, 241 insertions, 274 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 0f68b234c..63518e67f 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -42,14 +42,6 @@ jobs:
42 if: matrix.os == 'windows-latest' 42 if: matrix.os == 'windows-latest'
43 run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old 43 run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old
44 44
45 # Work around https://github.com/actions/cache/issues/403 by using GNU tar
46 # instead of BSD tar.
47 - name: Install GNU tar
48 if: matrix.os == 'macos-latest'
49 run: |
50 brew install gnu-tar
51 echo PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" >> $GITHUB_ENV
52
53 - name: Install Rust toolchain 45 - name: Install Rust toolchain
54 uses: actions-rs/toolchain@v1 46 uses: actions-rs/toolchain@v1
55 with: 47 with:
@@ -58,19 +50,8 @@ jobs:
58 override: true 50 override: true
59 components: rustfmt, rust-src 51 components: rustfmt, rust-src
60 52
61 - name: Cache cargo directories 53 - name: Cache Dependencies
62 uses: actions/cache@v2 54 uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
63 with:
64 path: |
65 ~/.cargo/registry
66 ~/.cargo/git
67 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
68
69 - name: Cache cargo target dir
70 uses: actions/cache@v2
71 with:
72 path: target
73 key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
74 55
75 - name: Compile 56 - name: Compile
76 run: cargo test --no-run --locked 57 run: cargo test --no-run --locked
@@ -78,9 +59,6 @@ jobs:
78 - name: Test 59 - name: Test
79 run: cargo test -- --nocapture 60 run: cargo test -- --nocapture
80 61
81 - name: Prepare cache
82 run: cargo xtask pre-cache
83
84 # Weird targets to catch non-portable code 62 # Weird targets to catch non-portable code
85 rust-cross: 63 rust-cross:
86 name: Rust Cross 64 name: Rust Cross
@@ -103,13 +81,8 @@ jobs:
103 - name: Install Rust targets 81 - name: Install Rust targets
104 run: rustup target add ${{ env.targets }} 82 run: rustup target add ${{ env.targets }}
105 83
106 - name: Cache cargo directories 84 - name: Cache Dependencies
107 uses: actions/cache@v2 85 uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
108 with:
109 path: |
110 ~/.cargo/registry
111 ~/.cargo/git
112 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
113 86
114 - name: Check 87 - name: Check
115 run: | 88 run: |
diff --git a/Cargo.lock b/Cargo.lock
index 1cfd704f6..0ca0b7b63 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -903,16 +903,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
903checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 903checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
904 904
905[[package]] 905[[package]]
906name = "memmap"
907version = "0.7.0"
908source = "registry+https://github.com/rust-lang/crates.io-index"
909checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
910dependencies = [
911 "libc",
912 "winapi",
913]
914
915[[package]]
916name = "memmap2" 906name = "memmap2"
917version = "0.2.2" 907version = "0.2.2"
918source = "registry+https://github.com/rust-lang/crates.io-index" 908source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1174,7 +1164,7 @@ dependencies = [
1174 "crossbeam-channel", 1164 "crossbeam-channel",
1175 "jod-thread", 1165 "jod-thread",
1176 "log", 1166 "log",
1177 "memmap", 1167 "memmap2",
1178 "object", 1168 "object",
1179 "profile", 1169 "profile",
1180 "serde", 1170 "serde",
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index 19e9f179e..112939948 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -187,7 +187,29 @@ pub(crate) struct AssistBuilder {
187 source_change: SourceChange, 187 source_change: SourceChange,
188 188
189 /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. 189 /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin.
190 mutated_tree: Option<(SyntaxNode, SyntaxNode)>, 190 mutated_tree: Option<TreeMutator>,
191}
192
193pub(crate) struct TreeMutator {
194 immutable: SyntaxNode,
195 mutable_clone: SyntaxNode,
196}
197
198impl TreeMutator {
199 pub(crate) fn new(immutable: &SyntaxNode) -> TreeMutator {
200 let immutable = immutable.ancestors().last().unwrap();
201 let mutable_clone = immutable.clone_for_update();
202 TreeMutator { immutable, mutable_clone }
203 }
204
205 pub(crate) fn make_mut<N: AstNode>(&self, node: &N) -> N {
206 N::cast(self.make_syntax_mut(node.syntax())).unwrap()
207 }
208
209 pub(crate) fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode {
210 let ptr = SyntaxNodePtr::new(node);
211 ptr.to_node(&self.mutable_clone)
212 }
191} 213}
192 214
193impl AssistBuilder { 215impl AssistBuilder {
@@ -206,8 +228,8 @@ impl AssistBuilder {
206 } 228 }
207 229
208 fn commit(&mut self) { 230 fn commit(&mut self) {
209 if let Some((old, new)) = self.mutated_tree.take() { 231 if let Some(tm) = self.mutated_tree.take() {
210 algo::diff(&old, &new).into_text_edit(&mut self.edit) 232 algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit)
211 } 233 }
212 234
213 let edit = mem::take(&mut self.edit).finish(); 235 let edit = mem::take(&mut self.edit).finish();
@@ -230,16 +252,7 @@ impl AssistBuilder {
230 /// phase, and then get their mutable couterparts using `make_mut` in the 252 /// phase, and then get their mutable couterparts using `make_mut` in the
231 /// mutable state. 253 /// mutable state.
232 pub(crate) fn make_mut(&mut self, node: SyntaxNode) -> SyntaxNode { 254 pub(crate) fn make_mut(&mut self, node: SyntaxNode) -> SyntaxNode {
233 let root = &self 255 self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node)
234 .mutated_tree
235 .get_or_insert_with(|| {
236 let immutable = node.ancestors().last().unwrap();
237 let mutable = immutable.clone_for_update();
238 (immutable, mutable)
239 })
240 .1;
241 let ptr = SyntaxNodePtr::new(&&node);
242 ptr.to_node(root)
243 } 256 }
244 257
245 /// Remove specified `range` of text. 258 /// Remove specified `range` of text.
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index b30652a9d..93b28370c 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -16,12 +16,13 @@ use syntax::{
16 edit::{AstNodeEdit, IndentLevel}, 16 edit::{AstNodeEdit, IndentLevel},
17 AstNode, 17 AstNode,
18 }, 18 },
19 ted,
19 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, 20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
20 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, 21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
21}; 22};
22 23
23use crate::{ 24use crate::{
24 assist_context::{AssistContext, Assists}, 25 assist_context::{AssistContext, Assists, TreeMutator},
25 AssistId, 26 AssistId,
26}; 27};
27 28
@@ -1366,7 +1367,10 @@ fn rewrite_body_segment(
1366 1367
1367/// change all usages to account for added `&`/`&mut` for some params 1368/// change all usages to account for added `&`/`&mut` for some params
1368fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode { 1369fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode {
1369 let mut rewriter = SyntaxRewriter::default(); 1370 let mut usages_for_param: Vec<(&Param, Vec<ast::Expr>)> = Vec::new();
1371
1372 let tm = TreeMutator::new(syntax);
1373
1370 for param in params { 1374 for param in params {
1371 if !param.kind().is_ref() { 1375 if !param.kind().is_ref() {
1372 continue; 1376 continue;
@@ -1376,30 +1380,39 @@ fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode)
1376 let usages = usages 1380 let usages = usages
1377 .iter() 1381 .iter()
1378 .filter(|reference| syntax.text_range().contains_range(reference.range)) 1382 .filter(|reference| syntax.text_range().contains_range(reference.range))
1379 .filter_map(|reference| path_element_of_reference(syntax, reference)); 1383 .filter_map(|reference| path_element_of_reference(syntax, reference))
1380 for path in usages { 1384 .map(|expr| tm.make_mut(&expr));
1381 match path.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { 1385
1386 usages_for_param.push((param, usages.collect()));
1387 }
1388
1389 let res = tm.make_syntax_mut(syntax);
1390
1391 for (param, usages) in usages_for_param {
1392 for usage in usages {
1393 match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
1382 Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => { 1394 Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => {
1383 // do nothing 1395 // do nothing
1384 } 1396 }
1385 Some(ast::Expr::RefExpr(node)) 1397 Some(ast::Expr::RefExpr(node))
1386 if param.kind() == ParamKind::MutRef && node.mut_token().is_some() => 1398 if param.kind() == ParamKind::MutRef && node.mut_token().is_some() =>
1387 { 1399 {
1388 rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap()); 1400 ted::replace(node.syntax(), node.expr().unwrap().syntax());
1389 } 1401 }
1390 Some(ast::Expr::RefExpr(node)) 1402 Some(ast::Expr::RefExpr(node))
1391 if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() => 1403 if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() =>
1392 { 1404 {
1393 rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap()); 1405 ted::replace(node.syntax(), node.expr().unwrap().syntax());
1394 } 1406 }
1395 Some(_) | None => { 1407 Some(_) | None => {
1396 rewriter.replace_ast(&path, &make::expr_prefix(T![*], path.clone())); 1408 let p = &make::expr_prefix(T![*], usage.clone()).clone_for_update();
1409 ted::replace(usage.syntax(), p.syntax())
1397 } 1410 }
1398 }; 1411 }
1399 } 1412 }
1400 } 1413 }
1401 1414
1402 rewriter.rewrite(syntax) 1415 res
1403} 1416}
1404 1417
1405fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode { 1418fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode {
diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs
index 72d889248..54a9a468e 100644
--- a/crates/ide_assists/src/handlers/reorder_impl.rs
+++ b/crates/ide_assists/src/handlers/reorder_impl.rs
@@ -79,9 +79,12 @@ pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
79 "Sort methods", 79 "Sort methods",
80 target, 80 target,
81 |builder| { 81 |builder| {
82 methods.into_iter().zip(sorted).for_each(|(old, new)| { 82 let methods =
83 ted::replace(builder.make_ast_mut(old).syntax(), new.clone_for_update().syntax()) 83 methods.into_iter().map(|fn_| builder.make_ast_mut(fn_)).collect::<Vec<_>>();
84 }); 84 methods
85 .into_iter()
86 .zip(sorted)
87 .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
85 }, 88 },
86 ) 89 )
87} 90}
@@ -160,7 +163,7 @@ $0impl Bar for Foo {}
160 } 163 }
161 164
162 #[test] 165 #[test]
163 fn reorder_impl_trait_methods() { 166 fn reorder_impl_trait_functions() {
164 check_assist( 167 check_assist(
165 reorder_impl, 168 reorder_impl,
166 r#" 169 r#"
@@ -197,4 +200,33 @@ impl Bar for Foo {
197 "#, 200 "#,
198 ) 201 )
199 } 202 }
203
204 #[test]
205 fn reorder_impl_trait_methods_uneven_ident_lengths() {
206 check_assist(
207 reorder_impl,
208 r#"
209trait Bar {
210 fn foo(&mut self) {}
211 fn fooo(&mut self) {}
212}
213
214struct Foo;
215impl Bar for Foo {
216 fn fooo(&mut self) {}
217 fn foo(&mut self) {$0}
218}"#,
219 r#"
220trait Bar {
221 fn foo(&mut self) {}
222 fn fooo(&mut self) {}
223}
224
225struct Foo;
226impl Bar for Foo {
227 fn foo(&mut self) {}
228 fn fooo(&mut self) {}
229}"#,
230 )
231 }
200} 232}
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 969249df6..d8f23d1eb 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -737,28 +737,6 @@ fn f() {}
737 } 737 }
738 738
739 #[test] 739 #[test]
740 fn completes_function() {
741 check(
742 r#"
743fn foo(
744 a: i32,
745 b: i32
746) {
747
748}
749
750fn main() {
751 fo$0
752}
753"#,
754 expect![[r#"
755 fn main() fn()
756 fn foo(…) fn(i32, i32)
757 "#]],
758 );
759 }
760
761 #[test]
762 fn completes_self_enum() { 740 fn completes_self_enum() {
763 check( 741 check(
764 r#" 742 r#"
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index b005bd773..f3fcb712c 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -301,103 +301,108 @@ impl<'a> CompletionContext<'a> {
301 .find_map(ast::Impl::cast); 301 .find_map(ast::Impl::cast);
302 } 302 }
303 303
304 fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
305 let mut node = match self.token.parent() {
306 Some(it) => it,
307 None => return (None, None),
308 };
309 loop {
310 break match_ast! {
311 match node {
312 ast::LetStmt(it) => {
313 cov_mark::hit!(expected_type_let_with_leading_char);
314 cov_mark::hit!(expected_type_let_without_leading_char);
315 let ty = it.pat()
316 .and_then(|pat| self.sema.type_of_pat(&pat));
317 let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() {
318 ident.name().map(NameOrNameRef::Name)
319 } else {
320 None
321 };
322
323 (ty, name)
324 },
325 ast::ArgList(_it) => {
326 cov_mark::hit!(expected_type_fn_param_with_leading_char);
327 cov_mark::hit!(expected_type_fn_param_without_leading_char);
328 ActiveParameter::at_token(
329 &self.sema,
330 self.token.clone(),
331 ).map(|ap| {
332 let name = ap.ident().map(NameOrNameRef::Name);
333 (Some(ap.ty), name)
334 })
335 .unwrap_or((None, None))
336 },
337 ast::RecordExprFieldList(_it) => {
338 cov_mark::hit!(expected_type_struct_field_without_leading_char);
339 self.token.prev_sibling_or_token()
340 .and_then(|se| se.into_node())
341 .and_then(|node| ast::RecordExprField::cast(node))
342 .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf)))
343 .map(|(f, rf)|(
344 Some(f.0.ty(self.db)),
345 rf.field_name().map(NameOrNameRef::NameRef),
346 ))
347 .unwrap_or((None, None))
348 },
349 ast::RecordExprField(it) => {
350 cov_mark::hit!(expected_type_struct_field_with_leading_char);
351 self.sema
352 .resolve_record_field(&it)
353 .map(|f|(
354 Some(f.0.ty(self.db)),
355 it.field_name().map(NameOrNameRef::NameRef),
356 ))
357 .unwrap_or((None, None))
358 },
359 ast::MatchExpr(it) => {
360 cov_mark::hit!(expected_type_match_arm_without_leading_char);
361 let ty = it.expr()
362 .and_then(|e| self.sema.type_of_expr(&e));
363 (ty, None)
364 },
365 ast::IfExpr(it) => {
366 cov_mark::hit!(expected_type_if_let_without_leading_char);
367 let ty = it.condition()
368 .and_then(|cond| cond.expr())
369 .and_then(|e| self.sema.type_of_expr(&e));
370 (ty, None)
371 },
372 ast::IdentPat(it) => {
373 cov_mark::hit!(expected_type_if_let_with_leading_char);
374 cov_mark::hit!(expected_type_match_arm_with_leading_char);
375 let ty = self.sema.type_of_pat(&ast::Pat::from(it));
376 (ty, None)
377 },
378 ast::Fn(it) => {
379 cov_mark::hit!(expected_type_fn_ret_with_leading_char);
380 cov_mark::hit!(expected_type_fn_ret_without_leading_char);
381 let def = self.sema.to_def(&it);
382 (def.map(|def| def.ret_type(self.db)), None)
383 },
384 ast::Stmt(it) => (None, None),
385 _ => {
386 match node.parent() {
387 Some(n) => {
388 node = n;
389 continue;
390 },
391 None => (None, None),
392 }
393 },
394 }
395 };
396 }
397 }
398
304 fn fill( 399 fn fill(
305 &mut self, 400 &mut self,
306 original_file: &SyntaxNode, 401 original_file: &SyntaxNode,
307 file_with_fake_ident: SyntaxNode, 402 file_with_fake_ident: SyntaxNode,
308 offset: TextSize, 403 offset: TextSize,
309 ) { 404 ) {
310 let (expected_type, expected_name) = { 405 let (expected_type, expected_name) = self.expected_type_and_name();
311 let mut node = match self.token.parent() {
312 Some(it) => it,
313 None => return,
314 };
315 loop {
316 break match_ast! {
317 match node {
318 ast::LetStmt(it) => {
319 cov_mark::hit!(expected_type_let_with_leading_char);
320 cov_mark::hit!(expected_type_let_without_leading_char);
321 let ty = it.pat()
322 .and_then(|pat| self.sema.type_of_pat(&pat));
323 let name = if let Some(ast::Pat::IdentPat(ident)) = it.pat() {
324 ident.name().map(NameOrNameRef::Name)
325 } else {
326 None
327 };
328
329 (ty, name)
330 },
331 ast::ArgList(_it) => {
332 cov_mark::hit!(expected_type_fn_param_with_leading_char);
333 cov_mark::hit!(expected_type_fn_param_without_leading_char);
334 ActiveParameter::at_token(
335 &self.sema,
336 self.token.clone(),
337 ).map(|ap| {
338 let name = ap.ident().map(NameOrNameRef::Name);
339 (Some(ap.ty), name)
340 })
341 .unwrap_or((None, None))
342 },
343 ast::RecordExprFieldList(_it) => {
344 cov_mark::hit!(expected_type_struct_field_without_leading_char);
345 self.token.prev_sibling_or_token()
346 .and_then(|se| se.into_node())
347 .and_then(|node| ast::RecordExprField::cast(node))
348 .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf)))
349 .map(|(f, rf)|(
350 Some(f.0.ty(self.db)),
351 rf.field_name().map(NameOrNameRef::NameRef),
352 ))
353 .unwrap_or((None, None))
354 },
355 ast::RecordExprField(it) => {
356 cov_mark::hit!(expected_type_struct_field_with_leading_char);
357 self.sema
358 .resolve_record_field(&it)
359 .map(|f|(
360 Some(f.0.ty(self.db)),
361 it.field_name().map(NameOrNameRef::NameRef),
362 ))
363 .unwrap_or((None, None))
364 },
365 ast::MatchExpr(it) => {
366 cov_mark::hit!(expected_type_match_arm_without_leading_char);
367 let ty = it.expr()
368 .and_then(|e| self.sema.type_of_expr(&e));
369
370 (ty, None)
371 },
372 ast::IdentPat(it) => {
373 cov_mark::hit!(expected_type_if_let_with_leading_char);
374 cov_mark::hit!(expected_type_match_arm_with_leading_char);
375 let ty = self.sema.type_of_pat(&ast::Pat::from(it));
376
377 (ty, None)
378 },
379 ast::Fn(_it) => {
380 cov_mark::hit!(expected_type_fn_ret_with_leading_char);
381 cov_mark::hit!(expected_type_fn_ret_without_leading_char);
382 let ty = self.token.ancestors()
383 .find_map(|ancestor| ast::Expr::cast(ancestor))
384 .and_then(|expr| self.sema.type_of_expr(&expr));
385
386 (ty, None)
387 },
388 _ => {
389 match node.parent() {
390 Some(n) => {
391 node = n;
392 continue;
393 },
394 None => (None, None),
395 }
396 },
397 }
398 };
399 }
400 };
401 self.expected_type = expected_type; 406 self.expected_type = expected_type;
402 self.expected_name = expected_name; 407 self.expected_name = expected_name;
403 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); 408 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
@@ -802,6 +807,7 @@ fn foo() {
802 807
803 #[test] 808 #[test]
804 fn expected_type_if_let_without_leading_char() { 809 fn expected_type_if_let_without_leading_char() {
810 cov_mark::check!(expected_type_if_let_without_leading_char);
805 check_expected_type_and_name( 811 check_expected_type_and_name(
806 r#" 812 r#"
807enum Foo { Bar, Baz, Quux } 813enum Foo { Bar, Baz, Quux }
@@ -811,8 +817,8 @@ fn foo() {
811 if let $0 = f { } 817 if let $0 = f { }
812} 818}
813"#, 819"#,
814 expect![[r#"ty: (), name: ?"#]], 820 expect![[r#"ty: Foo, name: ?"#]],
815 ) // FIXME should be `ty: u32, name: ?` 821 )
816 } 822 }
817 823
818 #[test] 824 #[test]
@@ -840,8 +846,8 @@ fn foo() -> u32 {
840 $0 846 $0
841} 847}
842"#, 848"#,
843 expect![[r#"ty: (), name: ?"#]], 849 expect![[r#"ty: u32, name: ?"#]],
844 ) // FIXME this should be `ty: u32, name: ?` 850 )
845 } 851 }
846 852
847 #[test] 853 #[test]
@@ -856,4 +862,16 @@ fn foo() -> u32 {
856 expect![[r#"ty: u32, name: ?"#]], 862 expect![[r#"ty: u32, name: ?"#]],
857 ) 863 )
858 } 864 }
865
866 #[test]
867 fn expected_type_fn_ret_fn_ref_fully_typed() {
868 check_expected_type_and_name(
869 r#"
870fn foo() -> u32 {
871 foo$0
872}
873"#,
874 expect![[r#"ty: u32, name: ?"#]],
875 )
876 }
859} 877}
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index 1ba1e4abd..2ce5eeedd 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -15,7 +15,7 @@ serde_json = { version = "1.0", features = ["unbounded_depth"] }
15log = "0.4.8" 15log = "0.4.8"
16crossbeam-channel = "0.5.0" 16crossbeam-channel = "0.5.0"
17jod-thread = "0.1.1" 17jod-thread = "0.1.1"
18memmap = "0.7.0" 18memmap2 = "0.2.0"
19object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } 19object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] }
20snap = "1.0" 20snap = "1.0"
21 21
diff --git a/crates/proc_macro_api/src/version.rs b/crates/proc_macro_api/src/version.rs
index dcf8fae8f..6dbac50b4 100644
--- a/crates/proc_macro_api/src/version.rs
+++ b/crates/proc_macro_api/src/version.rs
@@ -6,7 +6,7 @@ use std::{
6 path::Path, 6 path::Path,
7}; 7};
8 8
9use memmap::Mmap; 9use memmap2::Mmap;
10use object::read::{File as BinaryFile, Object, ObjectSection}; 10use object::read::{File as BinaryFile, Object, ObjectSection};
11use snap::read::FrameDecoder as SnapDecoder; 11use snap::read::FrameDecoder as SnapDecoder;
12 12
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 54195adb7..58722aaa3 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -611,6 +611,41 @@ For example, mutable bindings are underlined by default and you can override thi
611} 611}
612---- 612----
613 613
614Most themes doesn't support styling unsafe operations differently yet. You can fix this by adding overrides for the rules `operator.unsafe`, `function.unsafe`, and `method.unsafe`:
615
616[source,jsonc]
617----
618{
619 "editor.semanticTokenColorCustomizations": {
620 "rules": {
621 "operator.unsafe": "#ff6600",
622 "function.unsafe": "#ff6600"
623 "method.unsafe": "#ff6600"
624 }
625 },
626}
627----
628
629In addition to the top-level rules you can specify overrides for specific themes. For example, if you wanted to use a darker text color on a specific light theme, you might write:
630
631[source,jsonc]
632----
633{
634 "editor.semanticTokenColorCustomizations": {
635 "rules": {
636 "operator.unsafe": "#ff6600"
637 },
638 "[Ayu Light]": {
639 "rules": {
640 "operator.unsafe": "#572300"
641 }
642 }
643 },
644}
645----
646
647Make sure you include the brackets around the theme name. For example, use `"[Ayu Light]"` to customize the theme Ayu Light.
648
614==== Special `when` clause context for keybindings. 649==== Special `when` clause context for keybindings.
615You may use `inRustProject` context to configure keybindings for rust projects only. 650You may use `inRustProject` context to configure keybindings for rust projects only.
616For example: 651For example:
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 12a7fea1e..b6aa2f52a 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -66,6 +66,7 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
66 66
67fn dist_server(release_channel: &str) -> Result<()> { 67fn dist_server(release_channel: &str) -> Result<()> {
68 let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel); 68 let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
69 let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true");
69 let target = get_target(); 70 let target = get_target();
70 if target.contains("-linux-gnu") || target.contains("-linux-musl") { 71 if target.contains("-linux-gnu") || target.contains("-linux-musl") {
71 env::set_var("CC", "clang"); 72 env::set_var("CC", "clang");
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index f80a5dd16..69b3cb9c1 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -28,7 +28,6 @@ xflags::xflags! {
28 } 28 }
29 29
30 cmd fuzz-tests {} 30 cmd fuzz-tests {}
31 cmd pre-cache {}
32 31
33 cmd release { 32 cmd release {
34 optional --dry-run 33 optional --dry-run
@@ -62,7 +61,6 @@ pub enum XtaskCmd {
62 Help(Help), 61 Help(Help),
63 Install(Install), 62 Install(Install),
64 FuzzTests(FuzzTests), 63 FuzzTests(FuzzTests),
65 PreCache(PreCache),
66 Release(Release), 64 Release(Release),
67 Promote(Promote), 65 Promote(Promote),
68 Dist(Dist), 66 Dist(Dist),
@@ -88,9 +86,6 @@ pub struct Install {
88pub struct FuzzTests; 86pub struct FuzzTests;
89 87
90#[derive(Debug)] 88#[derive(Debug)]
91pub struct PreCache;
92
93#[derive(Debug)]
94pub struct Release { 89pub struct Release {
95 pub dry_run: bool, 90 pub dry_run: bool,
96} 91}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index ce3353410..d0bef7b7a 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -18,7 +18,6 @@ mod install;
18mod release; 18mod release;
19mod dist; 19mod dist;
20mod metrics; 20mod metrics;
21mod pre_cache;
22 21
23use anyhow::{bail, Result}; 22use anyhow::{bail, Result};
24use std::{ 23use std::{
@@ -39,7 +38,6 @@ fn main() -> Result<()> {
39 } 38 }
40 flags::XtaskCmd::Install(cmd) => cmd.run(), 39 flags::XtaskCmd::Install(cmd) => cmd.run(),
41 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), 40 flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
42 flags::XtaskCmd::PreCache(cmd) => cmd.run(),
43 flags::XtaskCmd::Release(cmd) => cmd.run(), 41 flags::XtaskCmd::Release(cmd) => cmd.run(),
44 flags::XtaskCmd::Promote(cmd) => cmd.run(), 42 flags::XtaskCmd::Promote(cmd) => cmd.run(),
45 flags::XtaskCmd::Dist(cmd) => cmd.run(), 43 flags::XtaskCmd::Dist(cmd) => cmd.run(),
diff --git a/xtask/src/pre_cache.rs b/xtask/src/pre_cache.rs
deleted file mode 100644
index b456224fd..000000000
--- a/xtask/src/pre_cache.rs
+++ /dev/null
@@ -1,79 +0,0 @@
1use std::{
2 fs::FileType,
3 path::{Path, PathBuf},
4};
5
6use anyhow::Result;
7use xshell::rm_rf;
8
9use crate::flags;
10
11impl flags::PreCache {
12 /// Cleans the `./target` dir after the build such that only
13 /// dependencies are cached on CI.
14 pub(crate) fn run(self) -> Result<()> {
15 let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
16 if !slow_tests_cookie.exists() {
17 panic!("slow tests were skipped on CI!")
18 }
19 rm_rf(slow_tests_cookie)?;
20
21 for path in read_dir("./target/debug", FileType::is_file)? {
22 // Can't delete yourself on windows :-(
23 if !path.ends_with("xtask.exe") {
24 rm_rf(&path)?
25 }
26 }
27
28 rm_rf("./target/.rustc_info.json")?;
29
30 let to_delete = read_dir("./crates", FileType::is_dir)?
31 .into_iter()
32 .map(|path| path.file_name().unwrap().to_string_lossy().replace('-', "_"))
33 .collect::<Vec<_>>();
34
35 for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
36 for path in read_dir(dir, |_file_type| true)? {
37 if path.ends_with("xtask.exe") {
38 continue;
39 }
40 let file_name = path.file_name().unwrap().to_string_lossy();
41 let (stem, _) = match rsplit_once(&file_name, '-') {
42 Some(it) => it,
43 None => {
44 rm_rf(path)?;
45 continue;
46 }
47 };
48 let stem = stem.replace('-', "_");
49 if to_delete.contains(&stem) {
50 rm_rf(path)?;
51 }
52 }
53 }
54
55 Ok(())
56 }
57}
58fn read_dir(path: impl AsRef<Path>, cond: impl Fn(&FileType) -> bool) -> Result<Vec<PathBuf>> {
59 read_dir_impl(path.as_ref(), &cond)
60}
61
62fn read_dir_impl(path: &Path, cond: &dyn Fn(&FileType) -> bool) -> Result<Vec<PathBuf>> {
63 let mut res = Vec::new();
64 for entry in path.read_dir()? {
65 let entry = entry?;
66 let file_type = entry.file_type()?;
67 if cond(&file_type) {
68 res.push(entry.path())
69 }
70 }
71 Ok(res)
72}
73
74fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
75 let mut split = haystack.rsplitn(2, delim);
76 let suffix = split.next()?;
77 let prefix = split.next()?;
78 Some((prefix, suffix))
79}