diff options
Diffstat (limited to 'crates')
29 files changed, 545 insertions, 400 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 3f940124c..37a050415 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -308,7 +308,11 @@ impl SourceAnalyzer { | |||
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) | 311 | if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { |
312 | resolve_hir_path_qualifier(db, &self.resolver, &hir_path) | ||
313 | } else { | ||
314 | resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) | ||
315 | } | ||
312 | } | 316 | } |
313 | 317 | ||
314 | pub(crate) fn record_literal_missing_fields( | 318 | pub(crate) fn record_literal_missing_fields( |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index e165b9c5f..1464320ba 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -197,7 +197,7 @@ fn eager_macro_recur( | |||
197 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 197 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
198 | mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), | 198 | mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), |
199 | ) -> Result<SyntaxNode, ErrorEmitted> { | 199 | ) -> Result<SyntaxNode, ErrorEmitted> { |
200 | let original = curr.value.clone().clone_for_update(); | 200 | let original = curr.value.clone_for_update(); |
201 | 201 | ||
202 | let children = original.descendants().filter_map(ast::MacroCall::cast); | 202 | let children = original.descendants().filter_map(ast::MacroCall::cast); |
203 | let mut replacements = Vec::new(); | 203 | let mut replacements = Vec::new(); |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 765a02b1c..03b97e7db 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -76,17 +76,17 @@ impl<'a> InferenceContext<'a> { | |||
76 | // way around first would mean we make the type variable `!`, instead of | 76 | // way around first would mean we make the type variable `!`, instead of |
77 | // just marking it as possibly diverging. | 77 | // just marking it as possibly diverging. |
78 | if self.coerce(&ty2, &ty1) { | 78 | if self.coerce(&ty2, &ty1) { |
79 | ty1.clone() | 79 | ty1 |
80 | } else if self.coerce(&ty1, &ty2) { | 80 | } else if self.coerce(&ty1, &ty2) { |
81 | ty2.clone() | 81 | ty2 |
82 | } else { | 82 | } else { |
83 | if let Some(id) = id { | 83 | if let Some(id) = id { |
84 | self.result | 84 | self.result |
85 | .type_mismatches | 85 | .type_mismatches |
86 | .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2.clone() }); | 86 | .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2 }); |
87 | } | 87 | } |
88 | cov_mark::hit!(coerce_merge_fail_fallback); | 88 | cov_mark::hit!(coerce_merge_fail_fallback); |
89 | ty1.clone() | 89 | ty1 |
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
@@ -183,7 +183,7 @@ impl<'a> InferenceContext<'a> { | |||
183 | // details of coercion errors though, so I think it's useful to leave | 183 | // details of coercion errors though, so I think it's useful to leave |
184 | // the structure like it is. | 184 | // the structure like it is. |
185 | 185 | ||
186 | let canonicalized = self.canonicalize(from_ty.clone()); | 186 | let canonicalized = self.canonicalize(from_ty); |
187 | let autoderef = autoderef::autoderef( | 187 | let autoderef = autoderef::autoderef( |
188 | self.db, | 188 | self.db, |
189 | self.resolver.krate(), | 189 | self.resolver.krate(), |
@@ -389,7 +389,7 @@ impl<'a> InferenceContext<'a> { | |||
389 | // The CoerceUnsized trait should have two generic params: Self and T. | 389 | // The CoerceUnsized trait should have two generic params: Self and T. |
390 | return Err(TypeError); | 390 | return Err(TypeError); |
391 | } | 391 | } |
392 | b.push(coerce_from.clone()).push(to_ty.clone()).build() | 392 | b.push(coerce_from).push(to_ty.clone()).build() |
393 | }; | 393 | }; |
394 | 394 | ||
395 | let goal: InEnvironment<DomainGoal> = | 395 | let goal: InEnvironment<DomainGoal> = |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 79a732106..97507305c 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -44,7 +44,7 @@ impl<'a> InferenceContext<'a> { | |||
44 | if !could_unify { | 44 | if !could_unify { |
45 | self.result.type_mismatches.insert( | 45 | self.result.type_mismatches.insert( |
46 | tgt_expr.into(), | 46 | tgt_expr.into(), |
47 | TypeMismatch { expected: expected_ty.clone(), actual: ty.clone() }, | 47 | TypeMismatch { expected: expected_ty, actual: ty.clone() }, |
48 | ); | 48 | ); |
49 | } | 49 | } |
50 | } | 50 | } |
@@ -57,15 +57,14 @@ impl<'a> InferenceContext<'a> { | |||
57 | let ty = self.infer_expr_inner(expr, &expected); | 57 | let ty = self.infer_expr_inner(expr, &expected); |
58 | let ty = if let Some(target) = expected.only_has_type(&mut self.table) { | 58 | let ty = if let Some(target) = expected.only_has_type(&mut self.table) { |
59 | if !self.coerce(&ty, &target) { | 59 | if !self.coerce(&ty, &target) { |
60 | self.result.type_mismatches.insert( | 60 | self.result |
61 | expr.into(), | 61 | .type_mismatches |
62 | TypeMismatch { expected: target.clone(), actual: ty.clone() }, | 62 | .insert(expr.into(), TypeMismatch { expected: target, actual: ty.clone() }); |
63 | ); | ||
64 | // Return actual type when type mismatch. | 63 | // Return actual type when type mismatch. |
65 | // This is needed for diagnostic when return type mismatch. | 64 | // This is needed for diagnostic when return type mismatch. |
66 | ty | 65 | ty |
67 | } else { | 66 | } else { |
68 | target.clone() | 67 | target |
69 | } | 68 | } |
70 | } else { | 69 | } else { |
71 | ty | 70 | ty |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 9c8e3b6ae..83e0a7a9e 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -196,7 +196,7 @@ impl<'a> InferenceContext<'a> { | |||
196 | let inner_ty = if let Some(subpat) = subpat { | 196 | let inner_ty = if let Some(subpat) = subpat { |
197 | self.infer_pat(*subpat, &expected, default_bm) | 197 | self.infer_pat(*subpat, &expected, default_bm) |
198 | } else { | 198 | } else { |
199 | expected.clone() | 199 | expected |
200 | }; | 200 | }; |
201 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | 201 | let inner_ty = self.insert_type_vars_shallow(inner_ty); |
202 | 202 | ||
@@ -266,10 +266,9 @@ impl<'a> InferenceContext<'a> { | |||
266 | // use a new type variable if we got error type here | 266 | // use a new type variable if we got error type here |
267 | let ty = self.insert_type_vars_shallow(ty); | 267 | let ty = self.insert_type_vars_shallow(ty); |
268 | if !self.unify(&ty, &expected) { | 268 | if !self.unify(&ty, &expected) { |
269 | self.result.type_mismatches.insert( | 269 | self.result |
270 | pat.into(), | 270 | .type_mismatches |
271 | TypeMismatch { expected: expected.clone(), actual: ty.clone() }, | 271 | .insert(pat.into(), TypeMismatch { expected: expected, actual: ty.clone() }); |
272 | ); | ||
273 | } | 272 | } |
274 | self.write_pat_ty(pat, ty.clone()); | 273 | self.write_pat_ty(pat, ty.clone()); |
275 | ty | 274 | ty |
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 5ebe7fd0e..b0c4ed60a 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -5,7 +5,7 @@ use ide_db::{ | |||
5 | helpers::visit_file_defs, | 5 | helpers::visit_file_defs, |
6 | RootDatabase, | 6 | RootDatabase, |
7 | }; | 7 | }; |
8 | use syntax::{ast::NameOwner, AstNode, TextRange, TextSize}; | 8 | use syntax::{ast::NameOwner, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | fn_references::find_all_methods, | 11 | fn_references::find_all_methods, |
@@ -80,26 +80,26 @@ pub(crate) fn annotations( | |||
80 | 80 | ||
81 | visit_file_defs(&Semantics::new(db), file_id, &mut |def| match def { | 81 | visit_file_defs(&Semantics::new(db), file_id, &mut |def| match def { |
82 | Either::Left(def) => { | 82 | Either::Left(def) => { |
83 | let node = match def { | 83 | let range = match def { |
84 | hir::ModuleDef::Const(konst) => { | 84 | hir::ModuleDef::Const(konst) => { |
85 | konst.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 85 | konst.source(db).and_then(|node| name_range(&node, file_id)) |
86 | } | 86 | } |
87 | hir::ModuleDef::Trait(trait_) => { | 87 | hir::ModuleDef::Trait(trait_) => { |
88 | trait_.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 88 | trait_.source(db).and_then(|node| name_range(&node, file_id)) |
89 | } | 89 | } |
90 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { | 90 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
91 | strukt.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 91 | strukt.source(db).and_then(|node| name_range(&node, file_id)) |
92 | } | 92 | } |
93 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { | 93 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { |
94 | enum_.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 94 | enum_.source(db).and_then(|node| name_range(&node, file_id)) |
95 | } | 95 | } |
96 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { | 96 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { |
97 | union.source(db).and_then(|node| range_and_position_of(&node, file_id)) | 97 | union.source(db).and_then(|node| name_range(&node, file_id)) |
98 | } | 98 | } |
99 | _ => None, | 99 | _ => None, |
100 | }; | 100 | }; |
101 | let (offset, range) = match node { | 101 | let (range, offset) = match range { |
102 | Some(node) => node, | 102 | Some(range) => (range, range.start()), |
103 | None => return, | 103 | None => return, |
104 | }; | 104 | }; |
105 | 105 | ||
@@ -122,18 +122,12 @@ pub(crate) fn annotations( | |||
122 | }); | 122 | }); |
123 | } | 123 | } |
124 | 124 | ||
125 | fn range_and_position_of<T: NameOwner>( | 125 | fn name_range<T: NameOwner>(node: &InFile<T>, file_id: FileId) -> Option<TextRange> { |
126 | node: &InFile<T>, | 126 | if node.file_id == file_id.into() { |
127 | file_id: FileId, | 127 | node.value.name().map(|it| it.syntax().text_range()) |
128 | ) -> Option<(TextSize, TextRange)> { | 128 | } else { |
129 | if node.file_id != file_id.into() { | ||
130 | // Node is outside the file we are adding annotations to (e.g. macros). | 129 | // Node is outside the file we are adding annotations to (e.g. macros). |
131 | None | 130 | None |
132 | } else { | ||
133 | Some(( | ||
134 | node.value.name()?.syntax().text_range().start(), | ||
135 | node.value.syntax().text_range(), | ||
136 | )) | ||
137 | } | 131 | } |
138 | } | 132 | } |
139 | } | 133 | } |
@@ -141,13 +135,15 @@ pub(crate) fn annotations( | |||
141 | }); | 135 | }); |
142 | 136 | ||
143 | if config.annotate_method_references { | 137 | if config.annotate_method_references { |
144 | annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation { | 138 | annotations.extend(find_all_methods(db, file_id).into_iter().map( |
145 | range: method.range, | 139 | |FileRange { file_id, range }| Annotation { |
146 | kind: AnnotationKind::HasReferences { | 140 | range, |
147 | position: FilePosition { file_id, offset: method.range.start() }, | 141 | kind: AnnotationKind::HasReferences { |
148 | data: None, | 142 | position: FilePosition { file_id, offset: range.start() }, |
143 | data: None, | ||
144 | }, | ||
149 | }, | 145 | }, |
150 | })); | 146 | )); |
151 | } | 147 | } |
152 | 148 | ||
153 | annotations | 149 | annotations |
@@ -266,7 +262,7 @@ fn main() { | |||
266 | }, | 262 | }, |
267 | }, | 263 | }, |
268 | Annotation { | 264 | Annotation { |
269 | range: 0..22, | 265 | range: 6..10, |
270 | kind: HasReferences { | 266 | kind: HasReferences { |
271 | position: FilePosition { | 267 | position: FilePosition { |
272 | file_id: FileId( | 268 | file_id: FileId( |
@@ -287,7 +283,7 @@ fn main() { | |||
287 | }, | 283 | }, |
288 | }, | 284 | }, |
289 | Annotation { | 285 | Annotation { |
290 | range: 24..48, | 286 | range: 30..36, |
291 | kind: HasReferences { | 287 | kind: HasReferences { |
292 | position: FilePosition { | 288 | position: FilePosition { |
293 | file_id: FileId( | 289 | file_id: FileId( |
@@ -370,7 +366,7 @@ fn main() { | |||
370 | }, | 366 | }, |
371 | }, | 367 | }, |
372 | Annotation { | 368 | Annotation { |
373 | range: 0..12, | 369 | range: 7..11, |
374 | kind: HasImpls { | 370 | kind: HasImpls { |
375 | position: FilePosition { | 371 | position: FilePosition { |
376 | file_id: FileId( | 372 | file_id: FileId( |
@@ -384,7 +380,7 @@ fn main() { | |||
384 | }, | 380 | }, |
385 | }, | 381 | }, |
386 | Annotation { | 382 | Annotation { |
387 | range: 0..12, | 383 | range: 7..11, |
388 | kind: HasReferences { | 384 | kind: HasReferences { |
389 | position: FilePosition { | 385 | position: FilePosition { |
390 | file_id: FileId( | 386 | file_id: FileId( |
@@ -478,7 +474,7 @@ fn main() { | |||
478 | }, | 474 | }, |
479 | }, | 475 | }, |
480 | Annotation { | 476 | Annotation { |
481 | range: 0..12, | 477 | range: 7..11, |
482 | kind: HasImpls { | 478 | kind: HasImpls { |
483 | position: FilePosition { | 479 | position: FilePosition { |
484 | file_id: FileId( | 480 | file_id: FileId( |
@@ -502,7 +498,7 @@ fn main() { | |||
502 | }, | 498 | }, |
503 | }, | 499 | }, |
504 | Annotation { | 500 | Annotation { |
505 | range: 0..12, | 501 | range: 7..11, |
506 | kind: HasReferences { | 502 | kind: HasReferences { |
507 | position: FilePosition { | 503 | position: FilePosition { |
508 | file_id: FileId( | 504 | file_id: FileId( |
@@ -529,7 +525,7 @@ fn main() { | |||
529 | }, | 525 | }, |
530 | }, | 526 | }, |
531 | Annotation { | 527 | Annotation { |
532 | range: 14..34, | 528 | range: 20..31, |
533 | kind: HasImpls { | 529 | kind: HasImpls { |
534 | position: FilePosition { | 530 | position: FilePosition { |
535 | file_id: FileId( | 531 | file_id: FileId( |
@@ -553,7 +549,7 @@ fn main() { | |||
553 | }, | 549 | }, |
554 | }, | 550 | }, |
555 | Annotation { | 551 | Annotation { |
556 | range: 14..34, | 552 | range: 20..31, |
557 | kind: HasReferences { | 553 | kind: HasReferences { |
558 | position: FilePosition { | 554 | position: FilePosition { |
559 | file_id: FileId( | 555 | file_id: FileId( |
@@ -712,7 +708,7 @@ fn main() { | |||
712 | }, | 708 | }, |
713 | }, | 709 | }, |
714 | Annotation { | 710 | Annotation { |
715 | range: 0..12, | 711 | range: 7..11, |
716 | kind: HasImpls { | 712 | kind: HasImpls { |
717 | position: FilePosition { | 713 | position: FilePosition { |
718 | file_id: FileId( | 714 | file_id: FileId( |
@@ -736,7 +732,7 @@ fn main() { | |||
736 | }, | 732 | }, |
737 | }, | 733 | }, |
738 | Annotation { | 734 | Annotation { |
739 | range: 0..12, | 735 | range: 7..11, |
740 | kind: HasReferences { | 736 | kind: HasReferences { |
741 | position: FilePosition { | 737 | position: FilePosition { |
742 | file_id: FileId( | 738 | file_id: FileId( |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index cf1a8bad7..79c2f4a1e 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -42,13 +42,107 @@ pub struct HlRange { | |||
42 | // Feature: Semantic Syntax Highlighting | 42 | // Feature: Semantic Syntax Highlighting |
43 | // | 43 | // |
44 | // rust-analyzer highlights the code semantically. | 44 | // rust-analyzer highlights the code semantically. |
45 | // For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. | 45 | // For example, `Bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. |
46 | // rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token. | 46 | // rust-analyzer does not specify colors directly, instead it assigns a tag (like `struct`) and a set of modifiers (like `declaration`) to each token. |
47 | // It's up to the client to map those to specific colors. | 47 | // It's up to the client to map those to specific colors. |
48 | // | 48 | // |
49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. | 49 | // The general rule is that a reference to an entity gets colored the same way as the entity itself. |
50 | // We also give special modifier for `mut` and `&mut` local variables. | 50 | // We also give special modifier for `mut` and `&mut` local variables. |
51 | // | 51 | // |
52 | // | ||
53 | // .Token Tags | ||
54 | // | ||
55 | // Rust-analyzer currently emits the following token tags: | ||
56 | // | ||
57 | // - For items: | ||
58 | // + | ||
59 | // [horizontal] | ||
60 | // enum:: Emitted for enums. | ||
61 | // function:: Emitted for free-standing functions. | ||
62 | // macro:: Emitted for macros. | ||
63 | // method:: Emitted for associated functions, also knowns as methods. | ||
64 | // namespace:: Emitted for modules. | ||
65 | // struct:: Emitted for structs. | ||
66 | // trait:: Emitted for traits. | ||
67 | // typeAlias:: Emitted for type aliases and `Self` in `impl`s. | ||
68 | // union:: Emitted for unions. | ||
69 | // | ||
70 | // - For literals: | ||
71 | // + | ||
72 | // [horizontal] | ||
73 | // boolean:: Emitted for the boolean literals `true` and `false`. | ||
74 | // character:: Emitted for character literals. | ||
75 | // number:: Emitted for numeric literals. | ||
76 | // string:: Emitted for string literals. | ||
77 | // escapeSequence:: Emitted for escaped sequences inside strings like `\n`. | ||
78 | // formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros. | ||
79 | // | ||
80 | // - For operators: | ||
81 | // + | ||
82 | // [horizontal] | ||
83 | // operator:: Emitted for general operators. | ||
84 | // arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`. | ||
85 | // bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`. | ||
86 | // comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`. | ||
87 | // logical:: Emitted for the logical operators `||`, `&&`, `!`. | ||
88 | // | ||
89 | // - For punctuation: | ||
90 | // + | ||
91 | // [horizontal] | ||
92 | // punctuation:: Emitted for general punctuation. | ||
93 | // angle:: Emitted for `<>` angle brackets. | ||
94 | // brace:: Emitted for `{}` braces. | ||
95 | // bracket:: Emitted for `[]` brackets. | ||
96 | // parenthesis:: Emitted for `()` parentheses. | ||
97 | // colon:: Emitted for the `:` token. | ||
98 | // comma:: Emitted for the `,` token. | ||
99 | // dot:: Emitted for the `.` token. | ||
100 | // Semi:: Emitted for the `;` token. | ||
101 | // | ||
102 | // //- | ||
103 | // | ||
104 | // [horizontal] | ||
105 | // attribute:: Emitted for attributes. | ||
106 | // builtinType:: Emitted for builtin types like `u32`, `str` and `f32`. | ||
107 | // comment:: Emitted for comments. | ||
108 | // constParameter:: Emitted for const parameters. | ||
109 | // enumMember:: Emitted for enum variants. | ||
110 | // generic:: Emitted for generic tokens that have no mapping. | ||
111 | // keyword:: Emitted for keywords. | ||
112 | // label:: Emitted for labels. | ||
113 | // lifetime:: Emitted for lifetimes. | ||
114 | // parameter:: Emitted for non-self function parameters. | ||
115 | // property:: Emitted for struct and union fields. | ||
116 | // selfKeyword:: Emitted for the self function parameter and self path-specifier. | ||
117 | // typeParameter:: Emitted for type parameters. | ||
118 | // unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of. | ||
119 | // variable:: Emitted for locals, constants and statics. | ||
120 | // | ||
121 | // | ||
122 | // .Token Modifiers | ||
123 | // | ||
124 | // Token modifiers allow to style some elements in the source code more precisely. | ||
125 | // | ||
126 | // Rust-analyzer currently emits the following token modifiers: | ||
127 | // | ||
128 | // [horizontal] | ||
129 | // async:: Emitted for async functions and the `async` and `await` keywords. | ||
130 | // attribute:: Emitted for tokens inside attributes. | ||
131 | // callable:: Emitted for locals whose types implements one of the `Fn*` traits. | ||
132 | // constant:: Emitted for consts. | ||
133 | // consuming:: Emitted for locals that are being consumed when use in a function call. | ||
134 | // controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator. | ||
135 | // declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`. | ||
136 | // documentation:: Emitted for documentation comments. | ||
137 | // injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation. | ||
138 | // intraDocLink:: Emitted for intra doc links in doc-strings. | ||
139 | // library:: Emitted for items that are defined outside of the current crate. | ||
140 | // mutable:: Emitted for mutable locals and statics. | ||
141 | // static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts. | ||
142 | // trait:: Emitted for associated trait items. | ||
143 | // unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token. | ||
144 | // | ||
145 | // | ||
52 | // image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] | 146 | // image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[] |
53 | // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] | 147 | // image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[] |
54 | pub(crate) fn highlight( | 148 | pub(crate) fn highlight( |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index b4a3d39c9..9503c936d 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -71,7 +71,7 @@ pub(super) fn element( | |||
71 | } | 71 | } |
72 | NAME_REF => { | 72 | NAME_REF => { |
73 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | 73 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); |
74 | highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { | 74 | highlight_func_by_name_ref(sema, krate, &name_ref).unwrap_or_else(|| { |
75 | let is_self = name_ref.self_token().is_some(); | 75 | let is_self = name_ref.self_token().is_some(); |
76 | let h = match NameRefClass::classify(sema, &name_ref) { | 76 | let h = match NameRefClass::classify(sema, &name_ref) { |
77 | Some(name_kind) => match name_kind { | 77 | Some(name_kind) => match name_kind { |
@@ -108,7 +108,7 @@ pub(super) fn element( | |||
108 | NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), | 108 | NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), |
109 | }, | 109 | }, |
110 | None if syntactic_name_ref_highlighting => { | 110 | None if syntactic_name_ref_highlighting => { |
111 | highlight_name_ref_by_syntax(name_ref, sema) | 111 | highlight_name_ref_by_syntax(name_ref, sema, krate) |
112 | } | 112 | } |
113 | None => HlTag::UnresolvedReference.into(), | 113 | None => HlTag::UnresolvedReference.into(), |
114 | }; | 114 | }; |
@@ -434,19 +434,23 @@ fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) | |||
434 | 434 | ||
435 | fn highlight_func_by_name_ref( | 435 | fn highlight_func_by_name_ref( |
436 | sema: &Semantics<RootDatabase>, | 436 | sema: &Semantics<RootDatabase>, |
437 | krate: Option<hir::Crate>, | ||
437 | name_ref: &ast::NameRef, | 438 | name_ref: &ast::NameRef, |
438 | ) -> Option<Highlight> { | 439 | ) -> Option<Highlight> { |
439 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; | 440 | let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; |
440 | highlight_method_call(sema, &mc) | 441 | highlight_method_call(sema, krate, &mc) |
441 | } | 442 | } |
442 | 443 | ||
443 | fn highlight_method_call( | 444 | fn highlight_method_call( |
444 | sema: &Semantics<RootDatabase>, | 445 | sema: &Semantics<RootDatabase>, |
446 | krate: Option<hir::Crate>, | ||
445 | method_call: &ast::MethodCallExpr, | 447 | method_call: &ast::MethodCallExpr, |
446 | ) -> Option<Highlight> { | 448 | ) -> Option<Highlight> { |
447 | let func = sema.resolve_method_call(&method_call)?; | 449 | let func = sema.resolve_method_call(&method_call)?; |
450 | |||
448 | let mut h = SymbolKind::Function.into(); | 451 | let mut h = SymbolKind::Function.into(); |
449 | h |= HlMod::Associated; | 452 | h |= HlMod::Associated; |
453 | |||
450 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { | 454 | if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { |
451 | h |= HlMod::Unsafe; | 455 | h |= HlMod::Unsafe; |
452 | } | 456 | } |
@@ -454,7 +458,10 @@ fn highlight_method_call( | |||
454 | h |= HlMod::Async; | 458 | h |= HlMod::Async; |
455 | } | 459 | } |
456 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { | 460 | if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() { |
457 | h |= HlMod::Trait | 461 | h |= HlMod::Trait; |
462 | } | ||
463 | if Some(func.module(sema.db).krate()) != krate { | ||
464 | h |= HlMod::Library; | ||
458 | } | 465 | } |
459 | 466 | ||
460 | if let Some(self_param) = func.self_param(sema.db) { | 467 | if let Some(self_param) = func.self_param(sema.db) { |
@@ -503,7 +510,11 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | |||
503 | tag.into() | 510 | tag.into() |
504 | } | 511 | } |
505 | 512 | ||
506 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { | 513 | fn highlight_name_ref_by_syntax( |
514 | name: ast::NameRef, | ||
515 | sema: &Semantics<RootDatabase>, | ||
516 | krate: Option<hir::Crate>, | ||
517 | ) -> Highlight { | ||
507 | let default = HlTag::UnresolvedReference; | 518 | let default = HlTag::UnresolvedReference; |
508 | 519 | ||
509 | let parent = match name.syntax().parent() { | 520 | let parent = match name.syntax().parent() { |
@@ -514,7 +525,7 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas | |||
514 | match parent.kind() { | 525 | match parent.kind() { |
515 | METHOD_CALL_EXPR => { | 526 | METHOD_CALL_EXPR => { |
516 | return ast::MethodCallExpr::cast(parent) | 527 | return ast::MethodCallExpr::cast(parent) |
517 | .and_then(|it| highlight_method_call(sema, &it)) | 528 | .and_then(|it| highlight_method_call(sema, krate, &it)) |
518 | .unwrap_or_else(|| SymbolKind::Function.into()); | 529 | .unwrap_or_else(|| SymbolKind::Function.into()); |
519 | } | 530 | } |
520 | FIELD_EXPR => { | 531 | FIELD_EXPR => { |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index e94f17cd9..9d481deae 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -37,6 +37,8 @@ pub enum HlTag { | |||
37 | None, | 37 | None, |
38 | } | 38 | } |
39 | 39 | ||
40 | // Don't forget to adjust the feature description in crates/ide/src/syntax_highlighting.rs. | ||
41 | // And make sure to use the lsp strings used when converting to the protocol in crates\rust-analyzer\src\semantic_tokens.rs, not the names of the variants here. | ||
40 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 42 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
41 | #[repr(u8)] | 43 | #[repr(u8)] |
42 | pub enum HlMod { | 44 | pub enum HlMod { |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 055d21109..0264e39a3 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -258,7 +258,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
258 | 258 | ||
259 | <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 259 | <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
260 | 260 | ||
261 | <span class="keyword control">if</span> <span class="keyword">let</span> <span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Die</span> <span class="operator">=</span> <span class="variable">control_flow</span> <span class="brace">{</span> | 261 | <span class="keyword control">if</span> <span class="variable">control_flow</span><span class="operator">.</span><span class="function associated consuming library">should_die</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
262 | foo::<span class="macro">die!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 262 | foo::<span class="macro">die!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
263 | <span class="brace">}</span> | 263 | <span class="brace">}</span> |
264 | <span class="brace">}</span> | 264 | <span class="brace">}</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index be4447ebb..662b53481 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -232,7 +232,7 @@ fn use_foo_items() { | |||
232 | 232 | ||
233 | let control_flow = foo::identity(foo::ControlFlow::Continue); | 233 | let control_flow = foo::identity(foo::ControlFlow::Continue); |
234 | 234 | ||
235 | if let foo::ControlFlow::Die = control_flow { | 235 | if control_flow.should_die() { |
236 | foo::die!(); | 236 | foo::die!(); |
237 | } | 237 | } |
238 | } | 238 | } |
@@ -249,6 +249,12 @@ pub enum ControlFlow { | |||
249 | Die, | 249 | Die, |
250 | } | 250 | } |
251 | 251 | ||
252 | impl ControlFlow { | ||
253 | pub fn should_die(self) -> bool { | ||
254 | matches!(self, ControlFlow::Die) | ||
255 | } | ||
256 | } | ||
257 | |||
252 | pub fn identity<T>(x: T) -> T { x } | 258 | pub fn identity<T>(x: T) -> T { x } |
253 | 259 | ||
254 | pub mod consts { | 260 | pub mod consts { |
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs index 79cb08d69..6da880b52 100644 --- a/crates/ide_assists/src/handlers/expand_glob_import.rs +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -55,7 +55,7 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
55 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; | 55 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; |
56 | let imported_defs = find_imported_defs(ctx, star)?; | 56 | let imported_defs = find_imported_defs(ctx, star)?; |
57 | 57 | ||
58 | let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); | 58 | let target = parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()); |
59 | acc.add( | 59 | acc.add( |
60 | AssistId("expand_glob_import", AssistKind::RefactorRewrite), | 60 | AssistId("expand_glob_import", AssistKind::RefactorRewrite), |
61 | "Expand glob import", | 61 | "Expand glob import", |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 9d5b61562..be9cfbded 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -110,13 +110,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
110 | if !ctx.config.enable_imports_on_the_fly { | 110 | if !ctx.config.enable_imports_on_the_fly { |
111 | return None; | 111 | return None; |
112 | } | 112 | } |
113 | if ctx.use_item_syntax.is_some() | 113 | if ctx.use_item_syntax.is_some() || ctx.is_path_disallowed() { |
114 | || ctx.attribute_under_caret.is_some() | ||
115 | || ctx.mod_declaration_under_caret.is_some() | ||
116 | || ctx.record_lit_syntax.is_some() | ||
117 | || ctx.has_trait_parent | ||
118 | || ctx.has_impl_parent | ||
119 | { | ||
120 | return None; | 114 | return None; |
121 | } | 115 | } |
122 | let potential_import_name = { | 116 | let potential_import_name = { |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 61b667104..58e35bad9 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use syntax::SyntaxKind; | 5 | use syntax::{SyntaxKind, T}; |
6 | 6 | ||
7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; |
8 | 8 | ||
@@ -49,78 +49,75 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
49 | return; | 49 | return; |
50 | } | 50 | } |
51 | 51 | ||
52 | let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; | 52 | let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent(); |
53 | if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { | 53 | let has_block_expr_parent = ctx.has_block_expr_parent(); |
54 | let has_item_list_parent = ctx.has_item_list_parent(); | ||
55 | if ctx.has_impl_or_trait_prev_sibling() { | ||
54 | add_keyword(ctx, acc, "where", "where "); | 56 | add_keyword(ctx, acc, "where", "where "); |
55 | return; | 57 | return; |
56 | } | 58 | } |
57 | if ctx.unsafe_is_prev { | 59 | if ctx.previous_token_is(T![unsafe]) { |
58 | if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { | 60 | if has_item_list_parent || has_block_expr_parent { |
59 | add_keyword(ctx, acc, "fn", "fn $0() {}") | 61 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") |
60 | } | 62 | } |
61 | 63 | ||
62 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 64 | if has_item_list_parent || has_block_expr_parent { |
63 | add_keyword(ctx, acc, "trait", "trait $0 {}"); | 65 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); |
64 | add_keyword(ctx, acc, "impl", "impl $0 {}"); | 66 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); |
65 | } | 67 | } |
66 | 68 | ||
67 | return; | 69 | return; |
68 | } | 70 | } |
69 | if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent | 71 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { |
70 | { | 72 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}"); |
71 | add_keyword(ctx, acc, "fn", "fn $0() {}"); | ||
72 | } | 73 | } |
73 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 74 | if has_item_list_parent || has_block_expr_parent { |
74 | add_keyword(ctx, acc, "use", "use "); | 75 | add_keyword(ctx, acc, "use", "use "); |
75 | add_keyword(ctx, acc, "impl", "impl $0 {}"); | 76 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); |
76 | add_keyword(ctx, acc, "trait", "trait $0 {}"); | 77 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); |
77 | } | 78 | } |
78 | 79 | ||
79 | if ctx.has_item_list_or_source_file_parent { | 80 | if has_item_list_parent { |
80 | add_keyword(ctx, acc, "enum", "enum $0 {}"); | 81 | add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); |
81 | add_keyword(ctx, acc, "struct", "struct $0"); | 82 | add_keyword(ctx, acc, "struct", "struct $0"); |
82 | add_keyword(ctx, acc, "union", "union $0 {}"); | 83 | add_keyword(ctx, acc, "union", "union $1 {\n $0\n}"); |
83 | } | 84 | } |
84 | 85 | ||
85 | if ctx.is_expr { | 86 | if ctx.is_expr { |
86 | add_keyword(ctx, acc, "match", "match $0 {}"); | 87 | add_keyword(ctx, acc, "match", "match $1 {\n $0\n}"); |
87 | add_keyword(ctx, acc, "while", "while $0 {}"); | 88 | add_keyword(ctx, acc, "while", "while $1 {\n $0\n}"); |
88 | add_keyword(ctx, acc, "while let", "while let $1 = $0 {}"); | 89 | add_keyword(ctx, acc, "while let", "while let $1 = $2 {\n $0\n}"); |
89 | add_keyword(ctx, acc, "loop", "loop {$0}"); | 90 | add_keyword(ctx, acc, "loop", "loop {\n $0\n}"); |
90 | add_keyword(ctx, acc, "if", "if $0 {}"); | 91 | add_keyword(ctx, acc, "if", "if $1 {\n $0\n}"); |
91 | add_keyword(ctx, acc, "if let", "if let $1 = $0 {}"); | 92 | add_keyword(ctx, acc, "if let", "if let $1 = $2 {\n $0\n}"); |
92 | add_keyword(ctx, acc, "for", "for $1 in $0 {}"); | 93 | add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}"); |
93 | } | 94 | } |
94 | 95 | ||
95 | if ctx.if_is_prev || ctx.block_expr_parent { | 96 | if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { |
96 | add_keyword(ctx, acc, "let", "let "); | 97 | add_keyword(ctx, acc, "let", "let "); |
97 | } | 98 | } |
98 | 99 | ||
99 | if ctx.after_if { | 100 | if ctx.after_if { |
100 | add_keyword(ctx, acc, "else", "else {$0}"); | 101 | add_keyword(ctx, acc, "else", "else {\n $0\n}"); |
101 | add_keyword(ctx, acc, "else if", "else if $0 {}"); | 102 | add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); |
102 | } | 103 | } |
103 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 104 | if has_item_list_parent || has_block_expr_parent { |
104 | add_keyword(ctx, acc, "mod", "mod $0"); | 105 | add_keyword(ctx, acc, "mod", "mod $0"); |
105 | } | 106 | } |
106 | if ctx.bind_pat_parent || ctx.ref_pat_parent { | 107 | if ctx.has_ident_or_ref_pat_parent() { |
107 | add_keyword(ctx, acc, "mut", "mut "); | 108 | add_keyword(ctx, acc, "mut", "mut "); |
108 | } | 109 | } |
109 | if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent | 110 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { |
110 | { | ||
111 | add_keyword(ctx, acc, "const", "const "); | 111 | add_keyword(ctx, acc, "const", "const "); |
112 | add_keyword(ctx, acc, "type", "type "); | 112 | add_keyword(ctx, acc, "type", "type "); |
113 | } | 113 | } |
114 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 114 | if has_item_list_parent || has_block_expr_parent { |
115 | add_keyword(ctx, acc, "static", "static "); | 115 | add_keyword(ctx, acc, "static", "static "); |
116 | }; | 116 | }; |
117 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 117 | if has_item_list_parent || has_block_expr_parent { |
118 | add_keyword(ctx, acc, "extern", "extern "); | 118 | add_keyword(ctx, acc, "extern", "extern "); |
119 | } | 119 | } |
120 | if ctx.has_item_list_or_source_file_parent | 120 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm |
121 | || has_trait_or_impl_parent | ||
122 | || ctx.block_expr_parent | ||
123 | || ctx.is_match_arm | ||
124 | { | 121 | { |
125 | add_keyword(ctx, acc, "unsafe", "unsafe "); | 122 | add_keyword(ctx, acc, "unsafe", "unsafe "); |
126 | } | 123 | } |
@@ -133,7 +130,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
133 | add_keyword(ctx, acc, "break", "break"); | 130 | add_keyword(ctx, acc, "break", "break"); |
134 | } | 131 | } |
135 | } | 132 | } |
136 | if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent { | 133 | if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() { |
137 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); | 134 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); |
138 | add_keyword(ctx, acc, "pub", "pub "); | 135 | add_keyword(ctx, acc, "pub", "pub "); |
139 | } | 136 | } |
@@ -141,7 +138,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
141 | if !ctx.is_trivial_path { | 138 | if !ctx.is_trivial_path { |
142 | return; | 139 | return; |
143 | } | 140 | } |
144 | let fn_def = match &ctx.function_syntax { | 141 | let fn_def = match &ctx.function_def { |
145 | Some(it) => it, | 142 | Some(it) => it, |
146 | None => return, | 143 | None => return, |
147 | }; | 144 | }; |
@@ -342,7 +339,9 @@ mod tests { | |||
342 | check_edit( | 339 | check_edit( |
343 | "else", | 340 | "else", |
344 | r#"fn quux() { if true { () } $0 }"#, | 341 | r#"fn quux() { if true { () } $0 }"#, |
345 | r#"fn quux() { if true { () } else {$0} }"#, | 342 | r#"fn quux() { if true { () } else { |
343 | $0 | ||
344 | } }"#, | ||
346 | ); | 345 | ); |
347 | } | 346 | } |
348 | 347 | ||
@@ -646,7 +645,9 @@ fn foo() { | |||
646 | fn main() { let x = $0 } | 645 | fn main() { let x = $0 } |
647 | "#, | 646 | "#, |
648 | r#" | 647 | r#" |
649 | fn main() { let x = match $0 {}; } | 648 | fn main() { let x = match $1 { |
649 | $0 | ||
650 | }; } | ||
650 | "#, | 651 | "#, |
651 | ); | 652 | ); |
652 | 653 | ||
@@ -660,7 +661,9 @@ fn main() { | |||
660 | "#, | 661 | "#, |
661 | r#" | 662 | r#" |
662 | fn main() { | 663 | fn main() { |
663 | let x = if $0 {}; | 664 | let x = if $1 { |
665 | $0 | ||
666 | }; | ||
664 | let y = 92; | 667 | let y = 92; |
665 | } | 668 | } |
666 | "#, | 669 | "#, |
@@ -676,7 +679,9 @@ fn main() { | |||
676 | "#, | 679 | "#, |
677 | r#" | 680 | r#" |
678 | fn main() { | 681 | fn main() { |
679 | let x = loop {$0}; | 682 | let x = loop { |
683 | $0 | ||
684 | }; | ||
680 | bar(); | 685 | bar(); |
681 | } | 686 | } |
682 | "#, | 687 | "#, |
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 5eeddf7a4..5f6285b84 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -8,19 +8,24 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) | |||
8 | if !ctx.lifetime_allowed { | 8 | if !ctx.lifetime_allowed { |
9 | return; | 9 | return; |
10 | } | 10 | } |
11 | let lp_string; | ||
11 | let param_lifetime = match ( | 12 | let param_lifetime = match ( |
12 | &ctx.lifetime_syntax, | 13 | &ctx.lifetime_syntax, |
13 | ctx.lifetime_param_syntax.as_ref().and_then(|lp| lp.lifetime()), | 14 | ctx.lifetime_param_syntax.as_ref().and_then(|lp| lp.lifetime()), |
14 | ) { | 15 | ) { |
15 | (Some(lt), Some(lp)) if lp == lt.clone() => return, | 16 | (Some(lt), Some(lp)) if lp == lt.clone() => return, |
16 | (Some(_), Some(lp)) => Some(lp.to_string()), | 17 | (Some(_), Some(lp)) => { |
18 | lp_string = lp.to_string(); | ||
19 | Some(&lp_string) | ||
20 | } | ||
17 | _ => None, | 21 | _ => None, |
18 | }; | 22 | }; |
19 | 23 | ||
20 | ctx.scope.process_all_names(&mut |name, res| { | 24 | ctx.scope.process_all_names(&mut |name, res| { |
21 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 25 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
22 | if param_lifetime != Some(name.to_string()) { | 26 | let name = name.to_string(); |
23 | acc.add_resolution(ctx, name.to_string(), &res); | 27 | if param_lifetime != Some(&name) { |
28 | acc.add_resolution(ctx, name, &res); | ||
24 | } | 29 | } |
25 | } | 30 | } |
26 | }); | 31 | }); |
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs index 2be299ac2..c5e377500 100644 --- a/crates/ide_completion/src/completions/macro_in_item_position.rs +++ b/crates/ide_completion/src/completions/macro_in_item_position.rs | |||
@@ -4,13 +4,15 @@ use crate::{CompletionContext, Completions}; | |||
4 | 4 | ||
5 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { | 5 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { |
6 | // Show only macros in top level. | 6 | // Show only macros in top level. |
7 | if ctx.is_new_item { | 7 | if !ctx.is_new_item { |
8 | ctx.scope.process_all_names(&mut |name, res| { | 8 | return; |
9 | if let hir::ScopeDef::MacroDef(mac) = res { | ||
10 | acc.add_macro(ctx, Some(name.to_string()), mac); | ||
11 | } | ||
12 | }) | ||
13 | } | 9 | } |
10 | |||
11 | ctx.scope.process_all_names(&mut |name, res| { | ||
12 | if let hir::ScopeDef::MacroDef(mac) = res { | ||
13 | acc.add_macro(ctx, Some(name.to_string()), mac); | ||
14 | } | ||
15 | }) | ||
14 | } | 16 | } |
15 | 17 | ||
16 | #[cfg(test)] | 18 | #[cfg(test)] |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 8dc9ab73c..b84e9a967 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -1,17 +1,15 @@ | |||
1 | //! Completes constants and paths in patterns. | 1 | //! Completes constants and paths in patterns. |
2 | 2 | ||
3 | use crate::{CompletionContext, Completions}; | 3 | use crate::{context::PatternRefutability, CompletionContext, Completions}; |
4 | 4 | ||
5 | /// Completes constants and paths in patterns. | 5 | /// Completes constants and paths in patterns. |
6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { |
7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_pat_binding) { | 7 | let refutable = match ctx.is_pat_or_const { |
8 | return; | 8 | Some(it) => it == PatternRefutability::Refutable, |
9 | } | 9 | None => return, |
10 | if ctx.record_pat_syntax.is_some() { | 10 | }; |
11 | return; | ||
12 | } | ||
13 | 11 | ||
14 | if !ctx.is_irrefutable_pat_binding { | 12 | if refutable { |
15 | if let Some(hir::Adt::Enum(e)) = | 13 | if let Some(hir::Adt::Enum(e)) = |
16 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 14 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
17 | { | 15 | { |
@@ -31,14 +29,14 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
31 | acc.add_struct_pat(ctx, *strukt, Some(name.clone())); | 29 | acc.add_struct_pat(ctx, *strukt, Some(name.clone())); |
32 | true | 30 | true |
33 | } | 31 | } |
34 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { | 32 | hir::ModuleDef::Variant(variant) if refutable => { |
35 | acc.add_variant_pat(ctx, *variant, Some(name.clone())); | 33 | acc.add_variant_pat(ctx, *variant, Some(name.clone())); |
36 | true | 34 | true |
37 | } | 35 | } |
38 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | 36 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) |
39 | | hir::ModuleDef::Variant(..) | 37 | | hir::ModuleDef::Variant(..) |
40 | | hir::ModuleDef::Const(..) | 38 | | hir::ModuleDef::Const(..) |
41 | | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding, | 39 | | hir::ModuleDef::Module(..) => refutable, |
42 | _ => false, | 40 | _ => false, |
43 | }, | 41 | }, |
44 | hir::ScopeDef::MacroDef(_) => true, | 42 | hir::ScopeDef::MacroDef(_) => true, |
@@ -47,7 +45,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
47 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | 45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); |
48 | true | 46 | true |
49 | } | 47 | } |
50 | Some(hir::Adt::Enum(_)) => !ctx.is_irrefutable_pat_binding, | 48 | Some(hir::Adt::Enum(_)) => refutable, |
51 | _ => true, | 49 | _ => true, |
52 | }, | 50 | }, |
53 | _ => false, | 51 | _ => false, |
@@ -402,4 +400,31 @@ impl Foo { | |||
402 | "#]], | 400 | "#]], |
403 | ) | 401 | ) |
404 | } | 402 | } |
403 | |||
404 | #[test] | ||
405 | fn completes_in_record_field_pat() { | ||
406 | check_snippet( | ||
407 | r#" | ||
408 | struct Foo { bar: Bar } | ||
409 | struct Bar(u32); | ||
410 | fn outer(Foo { bar: $0 }: Foo) {} | ||
411 | "#, | ||
412 | expect![[r#" | ||
413 | bn Foo Foo { bar$1 }$0 | ||
414 | bn Bar Bar($1)$0 | ||
415 | "#]], | ||
416 | ) | ||
417 | } | ||
418 | |||
419 | #[test] | ||
420 | fn skips_in_record_field_pat_name() { | ||
421 | check_snippet( | ||
422 | r#" | ||
423 | struct Foo { bar: Bar } | ||
424 | struct Bar(u32); | ||
425 | fn outer(Foo { bar$0 }: Foo) {} | ||
426 | "#, | ||
427 | expect![[r#""#]], | ||
428 | ) | ||
429 | } | ||
405 | } | 430 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index eedb44873..ed48f61af 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -7,21 +7,19 @@ use syntax::AstNode; | |||
7 | use crate::{CompletionContext, Completions}; | 7 | use crate::{CompletionContext, Completions}; |
8 | 8 | ||
9 | pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | if ctx.is_path_disallowed() { | ||
11 | return; | ||
12 | } | ||
10 | let path = match &ctx.path_qual { | 13 | let path = match &ctx.path_qual { |
11 | Some(path) => path.clone(), | 14 | Some(path) => path.clone(), |
12 | None => return, | 15 | None => return, |
13 | }; | 16 | }; |
14 | 17 | ||
15 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { | ||
16 | return; | ||
17 | } | ||
18 | |||
19 | let context_module = ctx.scope.module(); | ||
20 | |||
21 | let resolution = match ctx.sema.resolve_path(&path) { | 18 | let resolution = match ctx.sema.resolve_path(&path) { |
22 | Some(res) => res, | 19 | Some(res) => res, |
23 | None => return, | 20 | None => return, |
24 | }; | 21 | }; |
22 | let context_module = ctx.scope.module(); | ||
25 | 23 | ||
26 | // Add associated types on type parameters and `Self`. | 24 | // Add associated types on type parameters and `Self`. |
27 | resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { | 25 | resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { |
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 40006fb74..e1526b70b 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs | |||
@@ -13,20 +13,19 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
13 | let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone())); | 13 | let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone())); |
14 | let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); | 14 | let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); |
15 | let impl_default_trait = default_trait | 15 | let impl_default_trait = default_trait |
16 | .and_then(|default_trait| ty.map(|ty| ty.impls_trait(ctx.db, default_trait, &[]))) | 16 | .zip(ty) |
17 | .unwrap_or(false); | 17 | .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); |
18 | 18 | ||
19 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); | 19 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); |
20 | if impl_default_trait && !missing_fields.is_empty() { | 20 | if impl_default_trait && !missing_fields.is_empty() { |
21 | let completion_text = "..Default::default()"; | 21 | let completion_text = "..Default::default()"; |
22 | let completion_text = completion_text | ||
23 | .strip_prefix(ctx.token.to_string().as_str()) | ||
24 | .unwrap_or(completion_text); | ||
25 | let mut item = CompletionItem::new( | 22 | let mut item = CompletionItem::new( |
26 | CompletionKind::Snippet, | 23 | CompletionKind::Snippet, |
27 | ctx.source_range(), | 24 | ctx.source_range(), |
28 | "..Default::default()", | 25 | completion_text, |
29 | ); | 26 | ); |
27 | let completion_text = | ||
28 | completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); | ||
30 | item.insert_text(completion_text).kind(SymbolKind::Field); | 29 | item.insert_text(completion_text).kind(SymbolKind::Field); |
31 | item.add_to(acc); | 30 | item.add_to(acc); |
32 | } | 31 | } |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 14cfb61de..defc25b00 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -14,7 +14,7 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) | |||
14 | } | 14 | } |
15 | 15 | ||
16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
17 | if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { | 17 | if !(ctx.is_trivial_path && ctx.function_def.is_some()) { |
18 | return; | 18 | return; |
19 | } | 19 | } |
20 | let cap = match ctx.config.snippet_cap { | 20 | let cap = match ctx.config.snippet_cap { |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 7875500c1..046a393ae 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -9,11 +9,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
9 | if !ctx.is_trivial_path { | 9 | if !ctx.is_trivial_path { |
10 | return; | 10 | return; |
11 | } | 11 | } |
12 | if ctx.record_lit_syntax.is_some() | 12 | if ctx.is_path_disallowed() { |
13 | || ctx.record_pat_syntax.is_some() | ||
14 | || ctx.attribute_under_caret.is_some() | ||
15 | || ctx.mod_declaration_under_caret.is_some() | ||
16 | { | ||
17 | return; | 13 | return; |
18 | } | 14 | } |
19 | 15 | ||
@@ -86,7 +82,7 @@ fn quux(x: Option<Enum>) { | |||
86 | } | 82 | } |
87 | } | 83 | } |
88 | "#, | 84 | "#, |
89 | expect![[""]], | 85 | expect![[r#""#]], |
90 | ); | 86 | ); |
91 | } | 87 | } |
92 | 88 | ||
@@ -102,7 +98,7 @@ fn quux(x: Option<Enum>) { | |||
102 | } | 98 | } |
103 | } | 99 | } |
104 | "#, | 100 | "#, |
105 | expect![[""]], | 101 | expect![[r#""#]], |
106 | ); | 102 | ); |
107 | } | 103 | } |
108 | 104 | ||
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 2f3fb1710..66577df94 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -1,29 +1,53 @@ | |||
1 | //! See `CompletionContext` structure. | 1 | //! See `CompletionContext` structure. |
2 | 2 | ||
3 | use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; | 3 | use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; |
4 | use ide_db::base_db::{FilePosition, SourceDatabase}; | 4 | use ide_db::{ |
5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; | 5 | base_db::{FilePosition, SourceDatabase}, |
6 | call_info::ActiveParameter, | ||
7 | RootDatabase, | ||
8 | }; | ||
6 | use syntax::{ | 9 | use syntax::{ |
7 | algo::find_node_at_offset, | 10 | algo::find_node_at_offset, |
8 | ast::{self, NameOrNameRef, NameOwner}, | 11 | ast::{self, NameOrNameRef, NameOwner}, |
9 | match_ast, AstNode, NodeOrToken, | 12 | match_ast, AstNode, NodeOrToken, |
10 | SyntaxKind::*, | 13 | SyntaxKind::{self, *}, |
11 | SyntaxNode, SyntaxToken, TextRange, TextSize, | 14 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
12 | }; | 15 | }; |
13 | |||
14 | use text_edit::Indel; | 16 | use text_edit::Indel; |
15 | 17 | ||
16 | use crate::{ | 18 | use crate::{ |
17 | patterns::{ | 19 | patterns::{ |
18 | fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent, | 20 | for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, |
19 | has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent, | 21 | has_impl_parent, has_item_list_or_source_file_parent, has_prev_sibling, has_ref_parent, |
20 | has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling, | 22 | has_trait_parent, inside_impl_trait_block, is_in_loop_body, is_match_arm, previous_token, |
21 | has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm, | ||
22 | unsafe_is_prev, | ||
23 | }, | 23 | }, |
24 | CompletionConfig, | 24 | CompletionConfig, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
28 | pub(crate) enum PatternRefutability { | ||
29 | Refutable, | ||
30 | Irrefutable, | ||
31 | } | ||
32 | |||
33 | /// Direct parent container of the cursor position | ||
34 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
35 | pub(crate) enum ImmediateLocation { | ||
36 | Impl, | ||
37 | Trait, | ||
38 | RecordFieldList, | ||
39 | RefPatOrExpr, | ||
40 | IdentPat, | ||
41 | BlockExpr, | ||
42 | ItemList, | ||
43 | } | ||
44 | |||
45 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
46 | pub(crate) enum PrevSibling { | ||
47 | Trait, | ||
48 | Impl, | ||
49 | } | ||
50 | |||
27 | /// `CompletionContext` is created early during completion to figure out, where | 51 | /// `CompletionContext` is created early during completion to figure out, where |
28 | /// exactly is the cursor, syntax-wise. | 52 | /// exactly is the cursor, syntax-wise. |
29 | #[derive(Debug)] | 53 | #[derive(Debug)] |
@@ -41,23 +65,33 @@ pub(crate) struct CompletionContext<'a> { | |||
41 | pub(super) expected_name: Option<NameOrNameRef>, | 65 | pub(super) expected_name: Option<NameOrNameRef>, |
42 | pub(super) expected_type: Option<Type>, | 66 | pub(super) expected_type: Option<Type>, |
43 | pub(super) name_ref_syntax: Option<ast::NameRef>, | 67 | pub(super) name_ref_syntax: Option<ast::NameRef>, |
44 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | 68 | |
45 | pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, | ||
46 | pub(super) function_syntax: Option<ast::Fn>, | ||
47 | pub(super) use_item_syntax: Option<ast::Use>, | 69 | pub(super) use_item_syntax: Option<ast::Use>, |
70 | |||
71 | /// The parent function of the cursor position if it exists. | ||
72 | pub(super) function_def: Option<ast::Fn>, | ||
73 | /// The parent impl of the cursor position if it exists. | ||
74 | pub(super) impl_def: Option<ast::Impl>, | ||
75 | |||
76 | /// RecordExpr the token is a field of | ||
48 | pub(super) record_lit_syntax: Option<ast::RecordExpr>, | 77 | pub(super) record_lit_syntax: Option<ast::RecordExpr>, |
78 | /// RecordPat the token is a field of | ||
49 | pub(super) record_pat_syntax: Option<ast::RecordPat>, | 79 | pub(super) record_pat_syntax: Option<ast::RecordPat>, |
50 | pub(super) record_field_syntax: Option<ast::RecordExprField>, | 80 | |
51 | pub(super) impl_def: Option<ast::Impl>, | 81 | // potentially set if we are completing a lifetime |
82 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | ||
83 | pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, | ||
52 | pub(super) lifetime_allowed: bool, | 84 | pub(super) lifetime_allowed: bool, |
85 | pub(super) is_label_ref: bool, | ||
86 | |||
87 | // potentially set if we are completing a name | ||
88 | pub(super) is_pat_or_const: Option<PatternRefutability>, | ||
89 | pub(super) is_param: bool, | ||
90 | |||
91 | pub(super) completion_location: Option<ImmediateLocation>, | ||
92 | |||
53 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong | 93 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong |
54 | pub(super) active_parameter: Option<ActiveParameter>, | 94 | pub(super) active_parameter: Option<ActiveParameter>, |
55 | pub(super) is_param: bool, | ||
56 | pub(super) is_label_ref: bool, | ||
57 | /// If a name-binding or reference to a const in a pattern. | ||
58 | /// Irrefutable patterns (like let) are excluded. | ||
59 | pub(super) is_pat_binding_or_const: bool, | ||
60 | pub(super) is_irrefutable_pat_binding: bool, | ||
61 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 95 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
62 | pub(super) is_trivial_path: bool, | 96 | pub(super) is_trivial_path: bool, |
63 | /// If not a trivial path, the prefix (qualifier). | 97 | /// If not a trivial path, the prefix (qualifier). |
@@ -82,26 +116,17 @@ pub(crate) struct CompletionContext<'a> { | |||
82 | pub(super) has_type_args: bool, | 116 | pub(super) has_type_args: bool, |
83 | pub(super) attribute_under_caret: Option<ast::Attr>, | 117 | pub(super) attribute_under_caret: Option<ast::Attr>, |
84 | pub(super) mod_declaration_under_caret: Option<ast::Module>, | 118 | pub(super) mod_declaration_under_caret: Option<ast::Module>, |
85 | pub(super) unsafe_is_prev: bool, | 119 | pub(super) locals: Vec<(String, Local)>, |
86 | pub(super) if_is_prev: bool, | 120 | |
87 | pub(super) block_expr_parent: bool, | 121 | // keyword patterns |
88 | pub(super) bind_pat_parent: bool, | 122 | pub(super) previous_token: Option<SyntaxToken>, |
89 | pub(super) ref_pat_parent: bool, | 123 | pub(super) prev_sibling: Option<PrevSibling>, |
90 | pub(super) in_loop_body: bool, | 124 | pub(super) in_loop_body: bool, |
91 | pub(super) has_trait_parent: bool, | ||
92 | pub(super) has_impl_parent: bool, | ||
93 | pub(super) inside_impl_trait_block: bool, | ||
94 | pub(super) has_field_list_parent: bool, | ||
95 | pub(super) trait_as_prev_sibling: bool, | ||
96 | pub(super) impl_as_prev_sibling: bool, | ||
97 | pub(super) is_match_arm: bool, | 125 | pub(super) is_match_arm: bool, |
98 | pub(super) has_item_list_or_source_file_parent: bool, | ||
99 | pub(super) for_is_prev2: bool, | ||
100 | pub(super) fn_is_prev: bool, | ||
101 | pub(super) incomplete_let: bool, | 126 | pub(super) incomplete_let: bool, |
102 | pub(super) locals: Vec<(String, Local)>, | ||
103 | } | ||
104 | 127 | ||
128 | no_completion_required: bool, | ||
129 | } | ||
105 | impl<'a> CompletionContext<'a> { | 130 | impl<'a> CompletionContext<'a> { |
106 | pub(super) fn new( | 131 | pub(super) fn new( |
107 | db: &'a RootDatabase, | 132 | db: &'a RootDatabase, |
@@ -149,17 +174,15 @@ impl<'a> CompletionContext<'a> { | |||
149 | name_ref_syntax: None, | 174 | name_ref_syntax: None, |
150 | lifetime_syntax: None, | 175 | lifetime_syntax: None, |
151 | lifetime_param_syntax: None, | 176 | lifetime_param_syntax: None, |
152 | function_syntax: None, | 177 | function_def: None, |
153 | use_item_syntax: None, | 178 | use_item_syntax: None, |
154 | record_lit_syntax: None, | 179 | record_lit_syntax: None, |
155 | record_pat_syntax: None, | 180 | record_pat_syntax: None, |
156 | record_field_syntax: None, | ||
157 | impl_def: None, | 181 | impl_def: None, |
158 | active_parameter: ActiveParameter::at(db, position), | 182 | active_parameter: ActiveParameter::at(db, position), |
159 | is_label_ref: false, | 183 | is_label_ref: false, |
160 | is_param: false, | 184 | is_param: false, |
161 | is_pat_binding_or_const: false, | 185 | is_pat_or_const: None, |
162 | is_irrefutable_pat_binding: false, | ||
163 | is_trivial_path: false, | 186 | is_trivial_path: false, |
164 | path_qual: None, | 187 | path_qual: None, |
165 | after_if: false, | 188 | after_if: false, |
@@ -175,22 +198,12 @@ impl<'a> CompletionContext<'a> { | |||
175 | has_type_args: false, | 198 | has_type_args: false, |
176 | attribute_under_caret: None, | 199 | attribute_under_caret: None, |
177 | mod_declaration_under_caret: None, | 200 | mod_declaration_under_caret: None, |
178 | unsafe_is_prev: false, | 201 | previous_token: None, |
179 | if_is_prev: false, | ||
180 | block_expr_parent: false, | ||
181 | bind_pat_parent: false, | ||
182 | ref_pat_parent: false, | ||
183 | in_loop_body: false, | 202 | in_loop_body: false, |
184 | has_trait_parent: false, | 203 | completion_location: None, |
185 | has_impl_parent: false, | 204 | prev_sibling: None, |
186 | inside_impl_trait_block: false, | ||
187 | has_field_list_parent: false, | ||
188 | trait_as_prev_sibling: false, | ||
189 | impl_as_prev_sibling: false, | ||
190 | is_match_arm: false, | 205 | is_match_arm: false, |
191 | has_item_list_or_source_file_parent: false, | 206 | no_completion_required: false, |
192 | for_is_prev2: false, | ||
193 | fn_is_prev: false, | ||
194 | incomplete_let: false, | 207 | incomplete_let: false, |
195 | locals, | 208 | locals, |
196 | }; | 209 | }; |
@@ -245,7 +258,7 @@ impl<'a> CompletionContext<'a> { | |||
245 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. | 258 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. |
246 | /// - `for _ i$0` -- obviously, it'll be "in" keyword. | 259 | /// - `for _ i$0` -- obviously, it'll be "in" keyword. |
247 | pub(crate) fn no_completion_required(&self) -> bool { | 260 | pub(crate) fn no_completion_required(&self) -> bool { |
248 | (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 | 261 | self.no_completion_required |
249 | } | 262 | } |
250 | 263 | ||
251 | /// The range of the identifier that is being completed. | 264 | /// The range of the identifier that is being completed. |
@@ -264,33 +277,92 @@ impl<'a> CompletionContext<'a> { | |||
264 | } | 277 | } |
265 | } | 278 | } |
266 | 279 | ||
280 | pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool { | ||
281 | self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) | ||
282 | } | ||
283 | |||
284 | pub(crate) fn has_impl_or_trait_parent(&self) -> bool { | ||
285 | matches!( | ||
286 | self.completion_location, | ||
287 | Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl) | ||
288 | ) | ||
289 | } | ||
290 | |||
291 | pub(crate) fn has_block_expr_parent(&self) -> bool { | ||
292 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | ||
293 | } | ||
294 | |||
295 | pub(crate) fn has_item_list_parent(&self) -> bool { | ||
296 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | ||
297 | } | ||
298 | |||
299 | pub(crate) fn has_ident_or_ref_pat_parent(&self) -> bool { | ||
300 | matches!( | ||
301 | self.completion_location, | ||
302 | Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefPatOrExpr) | ||
303 | ) | ||
304 | } | ||
305 | |||
306 | pub(crate) fn has_impl_parent(&self) -> bool { | ||
307 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) | ||
308 | } | ||
309 | |||
310 | pub(crate) fn has_field_list_parent(&self) -> bool { | ||
311 | matches!(self.completion_location, Some(ImmediateLocation::RecordFieldList)) | ||
312 | } | ||
313 | |||
314 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { | ||
315 | self.prev_sibling.is_some() | ||
316 | } | ||
317 | |||
318 | pub(crate) fn is_path_disallowed(&self) -> bool { | ||
319 | self.record_lit_syntax.is_some() | ||
320 | || self.record_pat_syntax.is_some() | ||
321 | || self.attribute_under_caret.is_some() | ||
322 | || self.mod_declaration_under_caret.is_some() | ||
323 | || self.has_impl_or_trait_parent() | ||
324 | } | ||
325 | |||
267 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { | 326 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { |
268 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | 327 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); |
269 | let syntax_element = NodeOrToken::Token(fake_ident_token); | 328 | let syntax_element = NodeOrToken::Token(fake_ident_token); |
270 | self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); | 329 | self.previous_token = previous_token(syntax_element.clone()); |
271 | self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); | ||
272 | self.if_is_prev = if_is_prev(syntax_element.clone()); | ||
273 | self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); | ||
274 | self.ref_pat_parent = has_ref_parent(syntax_element.clone()); | ||
275 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); | 330 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); |
276 | self.has_trait_parent = has_trait_parent(syntax_element.clone()); | ||
277 | self.has_impl_parent = has_impl_parent(syntax_element.clone()); | ||
278 | self.inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
279 | self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); | ||
280 | self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); | ||
281 | self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); | ||
282 | self.is_match_arm = is_match_arm(syntax_element.clone()); | 331 | self.is_match_arm = is_match_arm(syntax_element.clone()); |
283 | self.has_item_list_or_source_file_parent = | 332 | if has_prev_sibling(syntax_element.clone(), IMPL) { |
284 | has_item_list_or_source_file_parent(syntax_element.clone()); | 333 | self.prev_sibling = Some(PrevSibling::Impl) |
334 | } else if has_prev_sibling(syntax_element.clone(), TRAIT) { | ||
335 | self.prev_sibling = Some(PrevSibling::Trait) | ||
336 | } | ||
337 | |||
338 | if has_block_expr_parent(syntax_element.clone()) { | ||
339 | self.completion_location = Some(ImmediateLocation::BlockExpr); | ||
340 | } else if has_bind_pat_parent(syntax_element.clone()) { | ||
341 | self.completion_location = Some(ImmediateLocation::IdentPat); | ||
342 | } else if has_ref_parent(syntax_element.clone()) { | ||
343 | self.completion_location = Some(ImmediateLocation::RefPatOrExpr); | ||
344 | } else if has_impl_parent(syntax_element.clone()) { | ||
345 | self.completion_location = Some(ImmediateLocation::Impl); | ||
346 | } else if has_field_list_parent(syntax_element.clone()) { | ||
347 | self.completion_location = Some(ImmediateLocation::RecordFieldList); | ||
348 | } else if has_trait_parent(syntax_element.clone()) { | ||
349 | self.completion_location = Some(ImmediateLocation::Trait); | ||
350 | } else if has_item_list_or_source_file_parent(syntax_element.clone()) { | ||
351 | self.completion_location = Some(ImmediateLocation::ItemList); | ||
352 | } | ||
353 | |||
285 | self.mod_declaration_under_caret = | 354 | self.mod_declaration_under_caret = |
286 | find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) | 355 | find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) |
287 | .filter(|module| module.item_list().is_none()); | 356 | .filter(|module| module.item_list().is_none()); |
288 | self.for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
289 | self.fn_is_prev = fn_is_prev(syntax_element.clone()); | ||
290 | self.incomplete_let = | 357 | self.incomplete_let = |
291 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { | 358 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { |
292 | it.syntax().text_range().end() == syntax_element.text_range().end() | 359 | it.syntax().text_range().end() == syntax_element.text_range().end() |
293 | }); | 360 | }); |
361 | |||
362 | let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
363 | let fn_is_prev = self.previous_token_is(T![fn]); | ||
364 | let for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
365 | self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2; | ||
294 | } | 366 | } |
295 | 367 | ||
296 | fn fill_impl_def(&mut self) { | 368 | fn fill_impl_def(&mut self) { |
@@ -412,67 +484,19 @@ impl<'a> CompletionContext<'a> { | |||
412 | self.expected_type = expected_type; | 484 | self.expected_type = expected_type; |
413 | self.expected_name = expected_name; | 485 | self.expected_name = expected_name; |
414 | self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); | 486 | self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); |
415 | 487 | let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { | |
416 | if let Some(lifetime) = find_node_at_offset::<ast::Lifetime>(&file_with_fake_ident, offset) | 488 | Some(it) => it, |
417 | { | 489 | None => return, |
418 | self.classify_lifetime(original_file, lifetime, offset); | 490 | }; |
419 | } | 491 | match name_like { |
420 | 492 | ast::NameLike::Lifetime(lifetime) => { | |
421 | // First, let's try to complete a reference to some declaration. | 493 | self.classify_lifetime(original_file, lifetime, offset); |
422 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) { | ||
423 | // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. | ||
424 | // See RFC#1685. | ||
425 | if is_node::<ast::Param>(name_ref.syntax()) { | ||
426 | self.is_param = true; | ||
427 | return; | ||
428 | } | ||
429 | // FIXME: remove this (V) duplication and make the check more precise | ||
430 | if name_ref.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() { | ||
431 | self.record_pat_syntax = | ||
432 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
433 | } | ||
434 | self.classify_name_ref(original_file, name_ref, offset); | ||
435 | } | ||
436 | |||
437 | // Otherwise, see if this is a declaration. We can use heuristics to | ||
438 | // suggest declaration names, see `CompletionKind::Magic`. | ||
439 | if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { | ||
440 | if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::IdentPat::cast) { | ||
441 | self.is_pat_binding_or_const = true; | ||
442 | if bind_pat.at_token().is_some() | ||
443 | || bind_pat.ref_token().is_some() | ||
444 | || bind_pat.mut_token().is_some() | ||
445 | { | ||
446 | self.is_pat_binding_or_const = false; | ||
447 | } | ||
448 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { | ||
449 | self.is_pat_binding_or_const = false; | ||
450 | } | ||
451 | if let Some(Some(pat)) = bind_pat.syntax().ancestors().find_map(|node| { | ||
452 | match_ast! { | ||
453 | match node { | ||
454 | ast::LetStmt(it) => Some(it.pat()), | ||
455 | ast::Param(it) => Some(it.pat()), | ||
456 | _ => None, | ||
457 | } | ||
458 | } | ||
459 | }) { | ||
460 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) { | ||
461 | self.is_pat_binding_or_const = false; | ||
462 | self.is_irrefutable_pat_binding = true; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | self.fill_impl_def(); | ||
467 | } | 494 | } |
468 | if is_node::<ast::Param>(name.syntax()) { | 495 | ast::NameLike::NameRef(name_ref) => { |
469 | self.is_param = true; | 496 | self.classify_name_ref(original_file, name_ref, offset); |
470 | return; | ||
471 | } | 497 | } |
472 | // FIXME: remove this (^) duplication and make the check more precise | 498 | ast::NameLike::Name(name) => { |
473 | if name.syntax().ancestors().find_map(ast::RecordPatFieldList::cast).is_some() { | 499 | self.classify_name(original_file, name, offset); |
474 | self.record_pat_syntax = | ||
475 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
476 | } | 500 | } |
477 | } | 501 | } |
478 | } | 502 | } |
@@ -506,22 +530,71 @@ impl<'a> CompletionContext<'a> { | |||
506 | } | 530 | } |
507 | } | 531 | } |
508 | 532 | ||
533 | fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) { | ||
534 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
535 | self.is_pat_or_const = Some(PatternRefutability::Refutable); | ||
536 | // if any of these is here our bind pat can't be a const pat anymore | ||
537 | let complex_ident_pat = bind_pat.at_token().is_some() | ||
538 | || bind_pat.ref_token().is_some() | ||
539 | || bind_pat.mut_token().is_some(); | ||
540 | if complex_ident_pat { | ||
541 | self.is_pat_or_const = None; | ||
542 | } else { | ||
543 | let irrefutable_pat = bind_pat.syntax().ancestors().find_map(|node| { | ||
544 | match_ast! { | ||
545 | match node { | ||
546 | ast::LetStmt(it) => Some(it.pat()), | ||
547 | ast::Param(it) => Some(it.pat()), | ||
548 | _ => None, | ||
549 | } | ||
550 | } | ||
551 | }); | ||
552 | if let Some(Some(pat)) = irrefutable_pat { | ||
553 | // This check is here since we could be inside a pattern in the initializer expression of the let statement. | ||
554 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) { | ||
555 | self.is_pat_or_const = Some(PatternRefutability::Irrefutable); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | let is_name_in_field_pat = bind_pat | ||
560 | .syntax() | ||
561 | .parent() | ||
562 | .and_then(ast::RecordPatField::cast) | ||
563 | .map_or(false, |pat_field| pat_field.name_ref().is_none()); | ||
564 | if is_name_in_field_pat { | ||
565 | self.is_pat_or_const = None; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | self.fill_impl_def(); | ||
570 | } | ||
571 | self.is_param |= is_node::<ast::Param>(name.syntax()); | ||
572 | if ast::RecordPatField::for_field_name(&name).is_some() { | ||
573 | self.record_pat_syntax = | ||
574 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
575 | } | ||
576 | } | ||
577 | |||
509 | fn classify_name_ref( | 578 | fn classify_name_ref( |
510 | &mut self, | 579 | &mut self, |
511 | original_file: &SyntaxNode, | 580 | original_file: &SyntaxNode, |
512 | name_ref: ast::NameRef, | 581 | name_ref: ast::NameRef, |
513 | offset: TextSize, | 582 | offset: TextSize, |
514 | ) { | 583 | ) { |
515 | self.name_ref_syntax = | 584 | self.fill_impl_def(); |
516 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | ||
517 | let name_range = name_ref.syntax().text_range(); | ||
518 | if ast::RecordExprField::for_field_name(&name_ref).is_some() { | 585 | if ast::RecordExprField::for_field_name(&name_ref).is_some() { |
519 | self.record_lit_syntax = | 586 | self.record_lit_syntax = |
520 | self.sema.find_node_at_offset_with_macros(original_file, offset); | 587 | self.sema.find_node_at_offset_with_macros(original_file, offset); |
521 | } | 588 | } |
589 | if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() { | ||
590 | self.record_pat_syntax = | ||
591 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
592 | } | ||
522 | 593 | ||
523 | self.fill_impl_def(); | 594 | self.name_ref_syntax = |
595 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | ||
524 | 596 | ||
597 | let name_range = name_ref.syntax().text_range(); | ||
525 | let top_node = name_ref | 598 | let top_node = name_ref |
526 | .syntax() | 599 | .syntax() |
527 | .ancestors() | 600 | .ancestors() |
@@ -529,31 +602,20 @@ impl<'a> CompletionContext<'a> { | |||
529 | .last() | 602 | .last() |
530 | .unwrap(); | 603 | .unwrap(); |
531 | 604 | ||
532 | match top_node.parent().map(|it| it.kind()) { | 605 | if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) { |
533 | Some(SOURCE_FILE) | Some(ITEM_LIST) => { | 606 | self.is_new_item = true; |
534 | self.is_new_item = true; | 607 | return; |
535 | return; | ||
536 | } | ||
537 | _ => (), | ||
538 | } | 608 | } |
539 | 609 | ||
540 | self.use_item_syntax = | 610 | self.use_item_syntax = |
541 | self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); | 611 | self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); |
542 | 612 | ||
543 | self.function_syntax = self | 613 | self.function_def = self |
544 | .sema | 614 | .sema |
545 | .token_ancestors_with_macros(self.token.clone()) | 615 | .token_ancestors_with_macros(self.token.clone()) |
546 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) | 616 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) |
547 | .find_map(ast::Fn::cast); | 617 | .find_map(ast::Fn::cast); |
548 | 618 | ||
549 | self.record_field_syntax = self | ||
550 | .sema | ||
551 | .token_ancestors_with_macros(self.token.clone()) | ||
552 | .take_while(|it| { | ||
553 | it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR | ||
554 | }) | ||
555 | .find_map(ast::RecordExprField::cast); | ||
556 | |||
557 | let parent = match name_ref.syntax().parent() { | 619 | let parent = match name_ref.syntax().parent() { |
558 | Some(it) => it, | 620 | Some(it) => it, |
559 | None => return, | 621 | None => return, |
@@ -626,6 +688,7 @@ impl<'a> CompletionContext<'a> { | |||
626 | } | 688 | } |
627 | } | 689 | } |
628 | } | 690 | } |
691 | |||
629 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 692 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { |
630 | // The receiver comes before the point of insertion of the fake | 693 | // The receiver comes before the point of insertion of the fake |
631 | // ident, so it should have the same range in the non-modified file | 694 | // ident, so it should have the same range in the non-modified file |
@@ -643,6 +706,7 @@ impl<'a> CompletionContext<'a> { | |||
643 | false | 706 | false |
644 | }; | 707 | }; |
645 | } | 708 | } |
709 | |||
646 | if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { | 710 | if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { |
647 | // As above | 711 | // As above |
648 | self.dot_receiver = method_call_expr | 712 | self.dot_receiver = method_call_expr |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index d82564381..04f2c532b 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -4,7 +4,7 @@ use syntax::{ | |||
4 | algo::non_trivia_sibling, | 4 | algo::non_trivia_sibling, |
5 | ast::{self, LoopBodyOwner}, | 5 | ast::{self, LoopBodyOwner}, |
6 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, | 6 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, |
7 | SyntaxKind::*, | 7 | SyntaxKind::{self, *}, |
8 | SyntaxNode, SyntaxToken, T, | 8 | SyntaxNode, SyntaxToken, T, |
9 | }; | 9 | }; |
10 | 10 | ||
@@ -73,6 +73,7 @@ fn test_has_block_expr_parent() { | |||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { |
74 | element.ancestors().any(|it| it.kind() == IDENT_PAT) | 74 | element.ancestors().any(|it| it.kind() == IDENT_PAT) |
75 | } | 75 | } |
76 | |||
76 | #[test] | 77 | #[test] |
77 | fn test_has_bind_pat_parent() { | 78 | fn test_has_bind_pat_parent() { |
78 | check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent); | 79 | check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent); |
@@ -91,11 +92,10 @@ fn test_has_ref_parent() { | |||
91 | } | 92 | } |
92 | 93 | ||
93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 94 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { |
94 | let ancestor = not_same_range_ancestor(element); | 95 | match not_same_range_ancestor(element) { |
95 | if !ancestor.is_some() { | 96 | Some(it) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST, |
96 | return true; | 97 | None => true, |
97 | } | 98 | } |
98 | ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some() | ||
99 | } | 99 | } |
100 | #[test] | 100 | #[test] |
101 | fn test_has_item_list_or_source_file_parent() { | 101 | fn test_has_item_list_or_source_file_parent() { |
@@ -115,36 +115,8 @@ fn test_is_match_arm() { | |||
115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); | 115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); |
116 | } | 116 | } |
117 | 117 | ||
118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { | 118 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { |
119 | element | 119 | element.into_token().and_then(|it| previous_non_trivia_token(it)) |
120 | .into_token() | ||
121 | .and_then(|it| previous_non_trivia_token(it)) | ||
122 | .filter(|it| it.kind() == T![unsafe]) | ||
123 | .is_some() | ||
124 | } | ||
125 | #[test] | ||
126 | fn test_unsafe_is_prev() { | ||
127 | check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev); | ||
128 | } | ||
129 | |||
130 | pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { | ||
131 | element | ||
132 | .into_token() | ||
133 | .and_then(|it| previous_non_trivia_token(it)) | ||
134 | .filter(|it| it.kind() == T![if]) | ||
135 | .is_some() | ||
136 | } | ||
137 | |||
138 | pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool { | ||
139 | element | ||
140 | .into_token() | ||
141 | .and_then(|it| previous_non_trivia_token(it)) | ||
142 | .filter(|it| it.kind() == T![fn]) | ||
143 | .is_some() | ||
144 | } | ||
145 | #[test] | ||
146 | fn test_fn_is_prev() { | ||
147 | check_pattern_is_applicable(r"fn l$0", fn_is_prev); | ||
148 | } | 120 | } |
149 | 121 | ||
150 | /// Check if the token previous to the previous one is `for`. | 122 | /// Check if the token previous to the previous one is `for`. |
@@ -162,47 +134,30 @@ fn test_for_is_prev2() { | |||
162 | check_pattern_is_applicable(r"for i i$0", for_is_prev2); | 134 | check_pattern_is_applicable(r"for i i$0", for_is_prev2); |
163 | } | 135 | } |
164 | 136 | ||
165 | #[test] | 137 | pub(crate) fn has_prev_sibling(element: SyntaxElement, kind: SyntaxKind) -> bool { |
166 | fn test_if_is_prev() { | 138 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == kind).is_some() |
167 | check_pattern_is_applicable(r"if l$0", if_is_prev); | ||
168 | } | ||
169 | |||
170 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | ||
171 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() | ||
172 | } | ||
173 | #[test] | ||
174 | fn test_has_trait_as_prev_sibling() { | ||
175 | check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling); | ||
176 | } | ||
177 | |||
178 | pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { | ||
179 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some() | ||
180 | } | 139 | } |
181 | #[test] | 140 | #[test] |
182 | fn test_has_impl_as_prev_sibling() { | 141 | fn test_has_impl_as_prev_sibling() { |
183 | check_pattern_is_applicable(r"impl A w$0 {}", has_impl_as_prev_sibling); | 142 | check_pattern_is_applicable(r"impl A w$0 {}", |it| has_prev_sibling(it, IMPL)); |
184 | } | 143 | } |
185 | 144 | ||
186 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 145 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { |
187 | for node in element.ancestors() { | 146 | element |
188 | if node.kind() == FN || node.kind() == CLOSURE_EXPR { | 147 | .ancestors() |
189 | break; | 148 | .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR) |
190 | } | 149 | .find_map(|it| { |
191 | let loop_body = match_ast! { | 150 | let loop_body = match_ast! { |
192 | match node { | 151 | match it { |
193 | ast::ForExpr(it) => it.loop_body(), | 152 | ast::ForExpr(it) => it.loop_body(), |
194 | ast::WhileExpr(it) => it.loop_body(), | 153 | ast::WhileExpr(it) => it.loop_body(), |
195 | ast::LoopExpr(it) => it.loop_body(), | 154 | ast::LoopExpr(it) => it.loop_body(), |
196 | _ => None, | 155 | _ => None, |
197 | } | 156 | } |
198 | }; | 157 | }; |
199 | if let Some(body) = loop_body { | 158 | loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range())) |
200 | if body.syntax().text_range().contains_range(element.text_range()) { | 159 | }) |
201 | return true; | 160 | .is_some() |
202 | } | ||
203 | } | ||
204 | } | ||
205 | false | ||
206 | } | 161 | } |
207 | 162 | ||
208 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { | 163 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d7f96b864..91300c56e 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -187,10 +187,7 @@ impl<'a> Render<'a> { | |||
187 | ScopeDef::ModuleDef(Function(func)) => { | 187 | ScopeDef::ModuleDef(Function(func)) => { |
188 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); | 188 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); |
189 | } | 189 | } |
190 | ScopeDef::ModuleDef(Variant(_)) | 190 | ScopeDef::ModuleDef(Variant(_)) if self.ctx.completion.is_pat_or_const.is_some() => { |
191 | if self.ctx.completion.is_pat_binding_or_const | ||
192 | | self.ctx.completion.is_irrefutable_pat_binding => | ||
193 | { | ||
194 | CompletionItemKind::SymbolKind(SymbolKind::Variant) | 191 | CompletionItemKind::SymbolKind(SymbolKind::Variant) |
195 | } | 192 | } |
196 | ScopeDef::ModuleDef(Variant(var)) => { | 193 | ScopeDef::ModuleDef(Variant(var)) => { |
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 91d6a4665..ae52dd8bb 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -420,6 +420,8 @@ fn trait_applicable_items( | |||
420 | 420 | ||
421 | let db = sema.db; | 421 | let db = sema.db; |
422 | 422 | ||
423 | let related_dyn_traits = | ||
424 | trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::<FxHashSet<_>>(); | ||
423 | let mut required_assoc_items = FxHashSet::default(); | 425 | let mut required_assoc_items = FxHashSet::default(); |
424 | let trait_candidates = items_locator::items_with_name( | 426 | let trait_candidates = items_locator::items_with_name( |
425 | sema, | 427 | sema, |
@@ -431,13 +433,15 @@ fn trait_applicable_items( | |||
431 | .filter_map(|input| item_as_assoc(db, input)) | 433 | .filter_map(|input| item_as_assoc(db, input)) |
432 | .filter_map(|assoc| { | 434 | .filter_map(|assoc| { |
433 | let assoc_item_trait = assoc.containing_trait(db)?; | 435 | let assoc_item_trait = assoc.containing_trait(db)?; |
434 | required_assoc_items.insert(assoc); | 436 | if related_dyn_traits.contains(&assoc_item_trait) { |
435 | Some(assoc_item_trait.into()) | 437 | None |
438 | } else { | ||
439 | required_assoc_items.insert(assoc); | ||
440 | Some(assoc_item_trait.into()) | ||
441 | } | ||
436 | }) | 442 | }) |
437 | .collect(); | 443 | .collect(); |
438 | 444 | ||
439 | let related_dyn_traits = | ||
440 | trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::<FxHashSet<_>>(); | ||
441 | let mut located_imports = FxHashSet::default(); | 445 | let mut located_imports = FxHashSet::default(); |
442 | 446 | ||
443 | if trait_assoc_item { | 447 | if trait_assoc_item { |
@@ -454,10 +458,6 @@ fn trait_applicable_items( | |||
454 | } | 458 | } |
455 | } | 459 | } |
456 | let located_trait = assoc.containing_trait(db)?; | 460 | let located_trait = assoc.containing_trait(db)?; |
457 | if related_dyn_traits.contains(&located_trait) { | ||
458 | return None; | ||
459 | } | ||
460 | |||
461 | let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); | 461 | let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); |
462 | let original_item = assoc_to_item(assoc); | 462 | let original_item = assoc_to_item(assoc); |
463 | located_imports.insert(LocatedImport::new( | 463 | located_imports.insert(LocatedImport::new( |
@@ -480,9 +480,6 @@ fn trait_applicable_items( | |||
480 | let assoc = function.as_assoc_item(db)?; | 480 | let assoc = function.as_assoc_item(db)?; |
481 | if required_assoc_items.contains(&assoc) { | 481 | if required_assoc_items.contains(&assoc) { |
482 | let located_trait = assoc.containing_trait(db)?; | 482 | let located_trait = assoc.containing_trait(db)?; |
483 | if related_dyn_traits.contains(&located_trait) { | ||
484 | return None; | ||
485 | } | ||
486 | let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); | 483 | let trait_item = ItemInNs::from(ModuleDef::from(located_trait)); |
487 | let original_item = assoc_to_item(assoc); | 484 | let original_item = assoc_to_item(assoc); |
488 | located_imports.insert(LocatedImport::new( | 485 | located_imports.insert(LocatedImport::new( |
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index 3aa546980..33a4f8168 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -214,7 +214,7 @@ impl WorkspaceBuildData { | |||
214 | acc | 214 | acc |
215 | }; | 215 | }; |
216 | let package_build_data = | 216 | let package_build_data = |
217 | res.per_package.entry(package_id.repr.clone()).or_default(); | 217 | res.per_package.entry(package_id.repr).or_default(); |
218 | // cargo_metadata crate returns default (empty) path for | 218 | // cargo_metadata crate returns default (empty) path for |
219 | // older cargos, which is not absolute, so work around that. | 219 | // older cargos, which is not absolute, so work around that. |
220 | if !out_dir.as_str().is_empty() { | 220 | if !out_dir.as_str().is_empty() { |
@@ -237,13 +237,13 @@ impl WorkspaceBuildData { | |||
237 | { | 237 | { |
238 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); | 238 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); |
239 | let package_build_data = | 239 | let package_build_data = |
240 | res.per_package.entry(package_id.repr.clone()).or_default(); | 240 | res.per_package.entry(package_id.repr).or_default(); |
241 | package_build_data.proc_macro_dylib_path = Some(filename); | 241 | package_build_data.proc_macro_dylib_path = Some(filename); |
242 | } | 242 | } |
243 | } | 243 | } |
244 | } | 244 | } |
245 | Message::CompilerMessage(message) => { | 245 | Message::CompilerMessage(message) => { |
246 | progress(message.target.name.clone()); | 246 | progress(message.target.name); |
247 | } | 247 | } |
248 | Message::BuildFinished(_) => {} | 248 | Message::BuildFinished(_) => {} |
249 | Message::TextLine(_) => {} | 249 | Message::TextLine(_) => {} |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index a8fee4f08..b8ad08364 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -346,11 +346,8 @@ impl CargoWorkspace { | |||
346 | 346 | ||
347 | let workspace_root = | 347 | let workspace_root = |
348 | AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string())); | 348 | AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string())); |
349 | let build_data_config = BuildDataConfig::new( | 349 | let build_data_config = |
350 | cargo_toml.to_path_buf(), | 350 | BuildDataConfig::new(cargo_toml.to_path_buf(), config.clone(), Arc::new(meta.packages)); |
351 | config.clone(), | ||
352 | Arc::new(meta.packages.clone()), | ||
353 | ); | ||
354 | 351 | ||
355 | Ok(CargoWorkspace { packages, targets, workspace_root, build_data_config }) | 352 | Ok(CargoWorkspace { packages, targets, workspace_root, build_data_config }) |
356 | } | 353 | } |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index 6129af95f..db216d951 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -46,7 +46,7 @@ define_semantic_token_types![ | |||
46 | (BRACE, "brace"), | 46 | (BRACE, "brace"), |
47 | (BRACKET, "bracket"), | 47 | (BRACKET, "bracket"), |
48 | (BUILTIN_TYPE, "builtinType"), | 48 | (BUILTIN_TYPE, "builtinType"), |
49 | (CHAR_LITERAL, "characterLiteral"), | 49 | (CHAR, "character"), |
50 | (COLON, "colon"), | 50 | (COLON, "colon"), |
51 | (COMMA, "comma"), | 51 | (COMMA, "comma"), |
52 | (COMPARISON, "comparison"), | 52 | (COMPARISON, "comparison"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index ca9513928..6d18d0ffc 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -466,7 +466,7 @@ fn semantic_token_type_and_modifiers( | |||
466 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, | 466 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, |
467 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, | 467 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, |
468 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, | 468 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, |
469 | HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL, | 469 | HlTag::CharLiteral => semantic_tokens::CHAR, |
470 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, | 470 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, |
471 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, | 471 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, |
472 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, | 472 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, |