diff options
author | Mikhail Rakhmanov <[email protected]> | 2020-06-13 07:42:15 +0100 |
---|---|---|
committer | Mikhail Rakhmanov <[email protected]> | 2020-06-13 07:42:15 +0100 |
commit | 16bbf4ab7f132e6e5e5318dccdef9a5d71afdd7f (patch) | |
tree | 4b79fa8c046be56b02427ba843e70cdf3ac05767 /crates | |
parent | eeb8b9e236796da8734ba81a49164864497f7226 (diff) | |
parent | b56ad148db0c69eb279c225f45d324b4e80e7367 (diff) |
Merge branch 'master' into keyword_completion
# Conflicts:
# docs/user/generated_features.adoc
Diffstat (limited to 'crates')
148 files changed, 6455 insertions, 2458 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 5b1a4680b..edd8255f4 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | //! See `AssistContext` | 1 | //! See `AssistContext` |
2 | 2 | ||
3 | use std::mem; | ||
4 | |||
3 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
4 | use hir::Semantics; | 6 | use hir::Semantics; |
5 | use ra_db::{FileId, FileRange}; | 7 | use ra_db::{FileId, FileRange}; |
@@ -170,13 +172,32 @@ impl Assists { | |||
170 | 172 | ||
171 | pub(crate) struct AssistBuilder { | 173 | pub(crate) struct AssistBuilder { |
172 | edit: TextEditBuilder, | 174 | edit: TextEditBuilder, |
173 | file: FileId, | 175 | file_id: FileId, |
174 | is_snippet: bool, | 176 | is_snippet: bool, |
177 | edits: Vec<SourceFileEdit>, | ||
175 | } | 178 | } |
176 | 179 | ||
177 | impl AssistBuilder { | 180 | impl AssistBuilder { |
178 | pub(crate) fn new(file: FileId) -> AssistBuilder { | 181 | pub(crate) fn new(file_id: FileId) -> AssistBuilder { |
179 | AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false } | 182 | AssistBuilder { |
183 | edit: TextEditBuilder::default(), | ||
184 | file_id, | ||
185 | is_snippet: false, | ||
186 | edits: Vec::new(), | ||
187 | } | ||
188 | } | ||
189 | |||
190 | pub(crate) fn edit_file(&mut self, file_id: FileId) { | ||
191 | self.file_id = file_id; | ||
192 | } | ||
193 | |||
194 | fn commit(&mut self) { | ||
195 | let edit = mem::take(&mut self.edit).finish(); | ||
196 | if !edit.is_empty() { | ||
197 | let new_edit = SourceFileEdit { file_id: self.file_id, edit }; | ||
198 | assert!(!self.edits.iter().any(|it| it.file_id == new_edit.file_id)); | ||
199 | self.edits.push(new_edit); | ||
200 | } | ||
180 | } | 201 | } |
181 | 202 | ||
182 | /// Remove specified `range` of text. | 203 | /// Remove specified `range` of text. |
@@ -234,21 +255,15 @@ impl AssistBuilder { | |||
234 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 255 | algo::diff(&node, &new).into_text_edit(&mut self.edit) |
235 | } | 256 | } |
236 | 257 | ||
237 | // FIXME: better API | ||
238 | pub(crate) fn set_file(&mut self, assist_file: FileId) { | ||
239 | self.file = assist_file; | ||
240 | } | ||
241 | |||
242 | // FIXME: kill this API | 258 | // FIXME: kill this API |
243 | /// Get access to the raw `TextEditBuilder`. | 259 | /// Get access to the raw `TextEditBuilder`. |
244 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { | 260 | pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder { |
245 | &mut self.edit | 261 | &mut self.edit |
246 | } | 262 | } |
247 | 263 | ||
248 | fn finish(self) -> SourceChange { | 264 | fn finish(mut self) -> SourceChange { |
249 | let edit = self.edit.finish(); | 265 | self.commit(); |
250 | let source_file_edit = SourceFileEdit { file_id: self.file, edit }; | 266 | let mut res: SourceChange = mem::take(&mut self.edits).into(); |
251 | let mut res: SourceChange = source_file_edit.into(); | ||
252 | if self.is_snippet { | 267 | if self.is_snippet { |
253 | res.is_snippet = true; | 268 | res.is_snippet = true; |
254 | } | 269 | } |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index ab20c6649..90b06a625 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -195,7 +195,7 @@ struct Test<K, T = u8> { | |||
195 | } | 195 | } |
196 | 196 | ||
197 | fn main() { | 197 | fn main() { |
198 | let test<|> = Test { t: 23, k: 33 }; | 198 | let test<|> = Test { t: 23u8, k: 33 }; |
199 | }"#, | 199 | }"#, |
200 | r#" | 200 | r#" |
201 | struct Test<K, T = u8> { | 201 | struct Test<K, T = u8> { |
@@ -204,7 +204,7 @@ struct Test<K, T = u8> { | |||
204 | } | 204 | } |
205 | 205 | ||
206 | fn main() { | 206 | fn main() { |
207 | let test: Test<i32> = Test { t: 23, k: 33 }; | 207 | let test: Test<i32> = Test { t: 23u8, k: 33 }; |
208 | }"#, | 208 | }"#, |
209 | ); | 209 | ); |
210 | } | 210 | } |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index 24f931a85..1cfbd75aa 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -64,7 +64,7 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
64 | let target = call.syntax().text_range(); | 64 | let target = call.syntax().text_range(); |
65 | acc.add(AssistId("add_function"), "Add function", target, |builder| { | 65 | acc.add(AssistId("add_function"), "Add function", target, |builder| { |
66 | let function_template = function_builder.render(); | 66 | let function_template = function_builder.render(); |
67 | builder.set_file(function_template.file); | 67 | builder.edit_file(function_template.file); |
68 | let new_fn = function_template.to_string(ctx.config.snippet_cap); | 68 | let new_fn = function_template.to_string(ctx.config.snippet_cap); |
69 | match ctx.config.snippet_cap { | 69 | match ctx.config.snippet_cap { |
70 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), | 70 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index edf96d50e..5092bf336 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -130,7 +130,7 @@ impl AutoImportAssets { | |||
130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { |
131 | let _p = profile("auto_import::search_for_imports"); | 131 | let _p = profile("auto_import::search_for_imports"); |
132 | let current_crate = self.module_with_name_to_import.krate(); | 132 | let current_crate = self.module_with_name_to_import.krate(); |
133 | ImportsLocator::new(db) | 133 | ImportsLocator::new(db, current_crate) |
134 | .find_imports(&self.get_search_query()) | 134 | .find_imports(&self.get_search_query()) |
135 | .into_iter() | 135 | .into_iter() |
136 | .filter_map(|candidate| match &self.import_candidate { | 136 | .filter_map(|candidate| match &self.import_candidate { |
@@ -841,4 +841,105 @@ fn main() { | |||
841 | ", | 841 | ", |
842 | ) | 842 | ) |
843 | } | 843 | } |
844 | |||
845 | #[test] | ||
846 | fn dep_import() { | ||
847 | check_assist( | ||
848 | auto_import, | ||
849 | r" | ||
850 | //- /lib.rs crate:dep | ||
851 | pub struct Struct; | ||
852 | |||
853 | //- /main.rs crate:main deps:dep | ||
854 | fn main() { | ||
855 | Struct<|> | ||
856 | }", | ||
857 | r"use dep::Struct; | ||
858 | |||
859 | fn main() { | ||
860 | Struct | ||
861 | } | ||
862 | ", | ||
863 | ); | ||
864 | } | ||
865 | |||
866 | #[test] | ||
867 | fn whole_segment() { | ||
868 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
869 | check_assist( | ||
870 | auto_import, | ||
871 | r" | ||
872 | //- /lib.rs crate:dep | ||
873 | pub mod fmt { | ||
874 | pub trait Display {} | ||
875 | } | ||
876 | |||
877 | pub fn panic_fmt() {} | ||
878 | |||
879 | //- /main.rs crate:main deps:dep | ||
880 | struct S; | ||
881 | |||
882 | impl f<|>mt::Display for S {}", | ||
883 | r"use dep::fmt; | ||
884 | |||
885 | struct S; | ||
886 | impl fmt::Display for S {} | ||
887 | ", | ||
888 | ); | ||
889 | } | ||
890 | |||
891 | #[test] | ||
892 | fn macro_generated() { | ||
893 | // Tests that macro-generated items are suggested from external crates. | ||
894 | check_assist( | ||
895 | auto_import, | ||
896 | r" | ||
897 | //- /lib.rs crate:dep | ||
898 | |||
899 | macro_rules! mac { | ||
900 | () => { | ||
901 | pub struct Cheese; | ||
902 | }; | ||
903 | } | ||
904 | |||
905 | mac!(); | ||
906 | |||
907 | //- /main.rs crate:main deps:dep | ||
908 | |||
909 | fn main() { | ||
910 | Cheese<|>; | ||
911 | }", | ||
912 | r"use dep::Cheese; | ||
913 | |||
914 | fn main() { | ||
915 | Cheese; | ||
916 | } | ||
917 | ", | ||
918 | ); | ||
919 | } | ||
920 | |||
921 | #[test] | ||
922 | fn casing() { | ||
923 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
924 | check_assist( | ||
925 | auto_import, | ||
926 | r" | ||
927 | //- /lib.rs crate:dep | ||
928 | |||
929 | pub struct FMT; | ||
930 | pub struct fmt; | ||
931 | |||
932 | //- /main.rs crate:main deps:dep | ||
933 | |||
934 | fn main() { | ||
935 | FMT<|>; | ||
936 | }", | ||
937 | r"use dep::FMT; | ||
938 | |||
939 | fn main() { | ||
940 | FMT; | ||
941 | } | ||
942 | ", | ||
943 | ); | ||
944 | } | ||
844 | } | 945 | } |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 4cc75a7ce..dfade7432 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -154,7 +154,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
154 | parent_block: &ast::BlockExpr, | 154 | parent_block: &ast::BlockExpr, |
155 | if_expr: &ast::IfExpr, | 155 | if_expr: &ast::IfExpr, |
156 | ) -> SyntaxNode { | 156 | ) -> SyntaxNode { |
157 | let then_block_items = then_block.dedent(IndentLevel::from(1)); | 157 | let then_block_items = then_block.dedent(IndentLevel(1)); |
158 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | 158 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); |
159 | let end_of_then = | 159 | let end_of_then = |
160 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | 160 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { |
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs new file mode 100644 index 000000000..44db7917a --- /dev/null +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -0,0 +1,320 @@ | |||
1 | use hir::{EnumVariant, Module, ModuleDef, Name}; | ||
2 | use ra_db::FileId; | ||
3 | use ra_fmt::leading_indent; | ||
4 | use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; | ||
5 | use ra_syntax::{ | ||
6 | algo::find_node_at_offset, | ||
7 | ast::{self, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, | ||
8 | SourceFile, SyntaxNode, TextRange, TextSize, | ||
9 | }; | ||
10 | use rustc_hash::FxHashSet; | ||
11 | |||
12 | use crate::{ | ||
13 | assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, Assists, | ||
14 | }; | ||
15 | |||
16 | // Assist: extract_struct_from_enum_variant | ||
17 | // | ||
18 | // Extracts a struct from enum variant. | ||
19 | // | ||
20 | // ``` | ||
21 | // enum A { <|>One(u32, u32) } | ||
22 | // ``` | ||
23 | // -> | ||
24 | // ``` | ||
25 | // struct One(pub u32, pub u32); | ||
26 | // | ||
27 | // enum A { One(One) } | ||
28 | // ``` | ||
29 | pub(crate) fn extract_struct_from_enum_variant( | ||
30 | acc: &mut Assists, | ||
31 | ctx: &AssistContext, | ||
32 | ) -> Option<()> { | ||
33 | let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; | ||
34 | let field_list = match variant.kind() { | ||
35 | ast::StructKind::Tuple(field_list) => field_list, | ||
36 | _ => return None, | ||
37 | }; | ||
38 | let variant_name = variant.name()?.to_string(); | ||
39 | let variant_hir = ctx.sema.to_def(&variant)?; | ||
40 | if existing_struct_def(ctx.db, &variant_name, &variant_hir) { | ||
41 | return None; | ||
42 | } | ||
43 | let enum_ast = variant.parent_enum(); | ||
44 | let visibility = enum_ast.visibility(); | ||
45 | let enum_hir = ctx.sema.to_def(&enum_ast)?; | ||
46 | let variant_hir_name = variant_hir.name(ctx.db); | ||
47 | let enum_module_def = ModuleDef::from(enum_hir); | ||
48 | let current_module = enum_hir.module(ctx.db); | ||
49 | let target = variant.syntax().text_range(); | ||
50 | acc.add( | ||
51 | AssistId("extract_struct_from_enum_variant"), | ||
52 | "Extract struct from enum variant", | ||
53 | target, | ||
54 | |builder| { | ||
55 | let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); | ||
56 | let res = definition.find_usages(&ctx.db, None); | ||
57 | let start_offset = variant.parent_enum().syntax().text_range().start(); | ||
58 | let mut visited_modules_set = FxHashSet::default(); | ||
59 | visited_modules_set.insert(current_module); | ||
60 | for reference in res { | ||
61 | let source_file = ctx.sema.parse(reference.file_range.file_id); | ||
62 | update_reference( | ||
63 | ctx, | ||
64 | builder, | ||
65 | reference, | ||
66 | &source_file, | ||
67 | &enum_module_def, | ||
68 | &variant_hir_name, | ||
69 | &mut visited_modules_set, | ||
70 | ); | ||
71 | } | ||
72 | extract_struct_def( | ||
73 | builder, | ||
74 | enum_ast.syntax(), | ||
75 | &variant_name, | ||
76 | &field_list.to_string(), | ||
77 | start_offset, | ||
78 | ctx.frange.file_id, | ||
79 | &visibility, | ||
80 | ); | ||
81 | let list_range = field_list.syntax().text_range(); | ||
82 | update_variant(builder, &variant_name, ctx.frange.file_id, list_range); | ||
83 | }, | ||
84 | ) | ||
85 | } | ||
86 | |||
87 | fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool { | ||
88 | variant | ||
89 | .parent_enum(db) | ||
90 | .module(db) | ||
91 | .scope(db, None) | ||
92 | .into_iter() | ||
93 | .any(|(name, _)| name.to_string() == variant_name.to_string()) | ||
94 | } | ||
95 | |||
96 | fn insert_import( | ||
97 | ctx: &AssistContext, | ||
98 | builder: &mut AssistBuilder, | ||
99 | path: &ast::PathExpr, | ||
100 | module: &Module, | ||
101 | enum_module_def: &ModuleDef, | ||
102 | variant_hir_name: &Name, | ||
103 | ) -> Option<()> { | ||
104 | let db = ctx.db; | ||
105 | let mod_path = module.find_use_path(db, enum_module_def.clone()); | ||
106 | if let Some(mut mod_path) = mod_path { | ||
107 | mod_path.segments.pop(); | ||
108 | mod_path.segments.push(variant_hir_name.clone()); | ||
109 | insert_use_statement(path.syntax(), &mod_path, ctx, builder.text_edit_builder()); | ||
110 | } | ||
111 | Some(()) | ||
112 | } | ||
113 | |||
114 | fn extract_struct_def( | ||
115 | builder: &mut AssistBuilder, | ||
116 | enum_ast: &SyntaxNode, | ||
117 | variant_name: &str, | ||
118 | variant_list: &str, | ||
119 | start_offset: TextSize, | ||
120 | file_id: FileId, | ||
121 | visibility: &Option<ast::Visibility>, | ||
122 | ) -> Option<()> { | ||
123 | let visibility_string = if let Some(visibility) = visibility { | ||
124 | format!("{} ", visibility.to_string()) | ||
125 | } else { | ||
126 | "".to_string() | ||
127 | }; | ||
128 | let indent = if let Some(indent) = leading_indent(enum_ast) { | ||
129 | indent.to_string() | ||
130 | } else { | ||
131 | "".to_string() | ||
132 | }; | ||
133 | let struct_def = format!( | ||
134 | r#"{}struct {}{}; | ||
135 | |||
136 | {}"#, | ||
137 | visibility_string, | ||
138 | variant_name, | ||
139 | list_with_visibility(variant_list), | ||
140 | indent | ||
141 | ); | ||
142 | builder.edit_file(file_id); | ||
143 | builder.insert(start_offset, struct_def); | ||
144 | Some(()) | ||
145 | } | ||
146 | |||
147 | fn update_variant( | ||
148 | builder: &mut AssistBuilder, | ||
149 | variant_name: &str, | ||
150 | file_id: FileId, | ||
151 | list_range: TextRange, | ||
152 | ) -> Option<()> { | ||
153 | let inside_variant_range = TextRange::new( | ||
154 | list_range.start().checked_add(TextSize::from(1))?, | ||
155 | list_range.end().checked_sub(TextSize::from(1))?, | ||
156 | ); | ||
157 | builder.edit_file(file_id); | ||
158 | builder.replace(inside_variant_range, variant_name); | ||
159 | Some(()) | ||
160 | } | ||
161 | |||
162 | fn update_reference( | ||
163 | ctx: &AssistContext, | ||
164 | builder: &mut AssistBuilder, | ||
165 | reference: Reference, | ||
166 | source_file: &SourceFile, | ||
167 | enum_module_def: &ModuleDef, | ||
168 | variant_hir_name: &Name, | ||
169 | visited_modules_set: &mut FxHashSet<Module>, | ||
170 | ) -> Option<()> { | ||
171 | let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>( | ||
172 | source_file.syntax(), | ||
173 | reference.file_range.range.start(), | ||
174 | )?; | ||
175 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | ||
176 | let list = call.arg_list()?; | ||
177 | let segment = path_expr.path()?.segment()?; | ||
178 | let module = ctx.sema.scope(&path_expr.syntax()).module()?; | ||
179 | let list_range = list.syntax().text_range(); | ||
180 | let inside_list_range = TextRange::new( | ||
181 | list_range.start().checked_add(TextSize::from(1))?, | ||
182 | list_range.end().checked_sub(TextSize::from(1))?, | ||
183 | ); | ||
184 | builder.edit_file(reference.file_range.file_id); | ||
185 | if !visited_modules_set.contains(&module) { | ||
186 | if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) | ||
187 | .is_some() | ||
188 | { | ||
189 | visited_modules_set.insert(module); | ||
190 | } | ||
191 | } | ||
192 | builder.replace(inside_list_range, format!("{}{}", segment, list)); | ||
193 | Some(()) | ||
194 | } | ||
195 | |||
196 | fn list_with_visibility(list: &str) -> String { | ||
197 | list.split(',') | ||
198 | .map(|part| { | ||
199 | let index = if part.chars().next().unwrap() == '(' { 1usize } else { 0 }; | ||
200 | let mut mod_part = part.trim().to_string(); | ||
201 | mod_part.insert_str(index, "pub "); | ||
202 | mod_part | ||
203 | }) | ||
204 | .collect::<Vec<String>>() | ||
205 | .join(", ") | ||
206 | } | ||
207 | |||
208 | #[cfg(test)] | ||
209 | mod tests { | ||
210 | |||
211 | use crate::{ | ||
212 | tests::{check_assist, check_assist_not_applicable}, | ||
213 | utils::FamousDefs, | ||
214 | }; | ||
215 | |||
216 | use super::*; | ||
217 | |||
218 | #[test] | ||
219 | fn test_extract_struct_several_fields() { | ||
220 | check_assist( | ||
221 | extract_struct_from_enum_variant, | ||
222 | "enum A { <|>One(u32, u32) }", | ||
223 | r#"struct One(pub u32, pub u32); | ||
224 | |||
225 | enum A { One(One) }"#, | ||
226 | ); | ||
227 | } | ||
228 | |||
229 | #[test] | ||
230 | fn test_extract_struct_one_field() { | ||
231 | check_assist( | ||
232 | extract_struct_from_enum_variant, | ||
233 | "enum A { <|>One(u32) }", | ||
234 | r#"struct One(pub u32); | ||
235 | |||
236 | enum A { One(One) }"#, | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn test_extract_struct_pub_visibility() { | ||
242 | check_assist( | ||
243 | extract_struct_from_enum_variant, | ||
244 | "pub enum A { <|>One(u32, u32) }", | ||
245 | r#"pub struct One(pub u32, pub u32); | ||
246 | |||
247 | pub enum A { One(One) }"#, | ||
248 | ); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn test_extract_struct_with_complex_imports() { | ||
253 | check_assist( | ||
254 | extract_struct_from_enum_variant, | ||
255 | r#"mod my_mod { | ||
256 | fn another_fn() { | ||
257 | let m = my_other_mod::MyEnum::MyField(1, 1); | ||
258 | } | ||
259 | |||
260 | pub mod my_other_mod { | ||
261 | fn another_fn() { | ||
262 | let m = MyEnum::MyField(1, 1); | ||
263 | } | ||
264 | |||
265 | pub enum MyEnum { | ||
266 | <|>MyField(u8, u8), | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | fn another_fn() { | ||
272 | let m = my_mod::my_other_mod::MyEnum::MyField(1, 1); | ||
273 | }"#, | ||
274 | r#"use my_mod::my_other_mod::MyField; | ||
275 | |||
276 | mod my_mod { | ||
277 | use my_other_mod::MyField; | ||
278 | |||
279 | fn another_fn() { | ||
280 | let m = my_other_mod::MyEnum::MyField(MyField(1, 1)); | ||
281 | } | ||
282 | |||
283 | pub mod my_other_mod { | ||
284 | fn another_fn() { | ||
285 | let m = MyEnum::MyField(MyField(1, 1)); | ||
286 | } | ||
287 | |||
288 | pub struct MyField(pub u8, pub u8); | ||
289 | |||
290 | pub enum MyEnum { | ||
291 | MyField(MyField), | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | fn another_fn() { | ||
297 | let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1)); | ||
298 | }"#, | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | fn check_not_applicable(ra_fixture: &str) { | ||
303 | let fixture = | ||
304 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
305 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | ||
310 | check_not_applicable("enum A { <|>One }"); | ||
311 | } | ||
312 | |||
313 | #[test] | ||
314 | fn test_extract_enum_not_applicable_if_struct_exists() { | ||
315 | check_not_applicable( | ||
316 | r#"struct One; | ||
317 | enum A { <|>One(u8) }"#, | ||
318 | ); | ||
319 | } | ||
320 | } | ||
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index 9ec42f568..531b3560f 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs | |||
@@ -63,7 +63,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O | |||
63 | }; | 63 | }; |
64 | 64 | ||
65 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | 65 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { |
66 | builder.set_file(target_file); | 66 | builder.edit_file(target_file); |
67 | match ctx.config.snippet_cap { | 67 | match ctx.config.snippet_cap { |
68 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | 68 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), |
69 | None => builder.insert(offset, format!("{} ", missing_visibility)), | 69 | None => builder.insert(offset, format!("{} ", missing_visibility)), |
@@ -106,7 +106,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
106 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); | 106 | format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); |
107 | 107 | ||
108 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { | 108 | acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { |
109 | builder.set_file(target_file); | 109 | builder.edit_file(target_file); |
110 | match ctx.config.snippet_cap { | 110 | match ctx.config.snippet_cap { |
111 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | 111 | Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), |
112 | None => builder.insert(offset, format!("{} ", missing_visibility)), | 112 | None => builder.insert(offset, format!("{} ", missing_visibility)), |
diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs index beb5b7366..28fcbc9ba 100644 --- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -41,8 +41,6 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) - | |||
41 | if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { | 41 | if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { |
42 | generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) | 42 | generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) |
43 | } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { | 43 | } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { |
44 | // only allow naming the last anonymous lifetime | ||
45 | lifetime_token.next_token().filter(|tok| tok.kind() == SyntaxKind::R_ANGLE)?; | ||
46 | generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) | 44 | generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) |
47 | } else { | 45 | } else { |
48 | None | 46 | None |
@@ -191,6 +189,23 @@ mod tests { | |||
191 | } | 189 | } |
192 | 190 | ||
193 | #[test] | 191 | #[test] |
192 | fn test_impl_with_other_type_param() { | ||
193 | check_assist( | ||
194 | introduce_named_lifetime, | ||
195 | "impl<I> fmt::Display for SepByBuilder<'_<|>, I> | ||
196 | where | ||
197 | I: Iterator, | ||
198 | I::Item: fmt::Display, | ||
199 | {", | ||
200 | "impl<I, 'a> fmt::Display for SepByBuilder<'a, I> | ||
201 | where | ||
202 | I: Iterator, | ||
203 | I::Item: fmt::Display, | ||
204 | {", | ||
205 | ) | ||
206 | } | ||
207 | |||
208 | #[test] | ||
194 | fn test_example_case_cursor_before_tick() { | 209 | fn test_example_case_cursor_before_tick() { |
195 | check_assist( | 210 | check_assist( |
196 | introduce_named_lifetime, | 211 | introduce_named_lifetime, |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index e016f51c3..dfcd787de 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -51,6 +51,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
51 | acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { | 51 | acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { |
52 | let match_expr = { | 52 | let match_expr = { |
53 | let then_arm = { | 53 | let then_arm = { |
54 | let then_block = then_block.reset_indent().indent(IndentLevel(1)); | ||
54 | let then_expr = unwrap_trivial_block(then_block); | 55 | let then_expr = unwrap_trivial_block(then_block); |
55 | make::match_arm(vec![pat.clone()], then_expr) | 56 | make::match_arm(vec![pat.clone()], then_expr) |
56 | }; | 57 | }; |
@@ -64,8 +65,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
64 | let else_expr = unwrap_trivial_block(else_block); | 65 | let else_expr = unwrap_trivial_block(else_block); |
65 | make::match_arm(vec![pattern], else_expr) | 66 | make::match_arm(vec![pattern], else_expr) |
66 | }; | 67 | }; |
67 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | 68 | let match_expr = make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])); |
68 | .indent(IndentLevel::from_node(if_expr.syntax())) | 69 | match_expr.indent(IndentLevel::from_node(if_expr.syntax())) |
69 | }; | 70 | }; |
70 | 71 | ||
71 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 72 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
@@ -213,4 +214,36 @@ fn foo(x: Result<i32, ()>) { | |||
213 | "#, | 214 | "#, |
214 | ); | 215 | ); |
215 | } | 216 | } |
217 | |||
218 | #[test] | ||
219 | fn nested_indent() { | ||
220 | check_assist( | ||
221 | replace_if_let_with_match, | ||
222 | r#" | ||
223 | fn main() { | ||
224 | if true { | ||
225 | <|>if let Ok(rel_path) = path.strip_prefix(root_path) { | ||
226 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
227 | Some((*id, rel_path)) | ||
228 | } else { | ||
229 | None | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | "#, | ||
234 | r#" | ||
235 | fn main() { | ||
236 | if true { | ||
237 | match path.strip_prefix(root_path) { | ||
238 | Ok(rel_path) => { | ||
239 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
240 | Some((*id, rel_path)) | ||
241 | } | ||
242 | _ => None, | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | "#, | ||
247 | ) | ||
248 | } | ||
216 | } | 249 | } |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 8440c7d0f..1fb13f481 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | 1 | use ra_fmt::unwrap_trivial_block; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, ElseBranch, Expr, LoopBodyOwner}, | 3 | ast::{ |
4 | match_ast, AstNode, TextRange, T, | 4 | self, |
5 | edit::{AstNodeEdit, IndentLevel}, | ||
6 | }, | ||
7 | AstNode, TextRange, T, | ||
5 | }; | 8 | }; |
6 | 9 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 10 | use crate::{AssistContext, AssistId, Assists}; |
@@ -24,94 +27,73 @@ use crate::{AssistContext, AssistId, Assists}; | |||
24 | // } | 27 | // } |
25 | // ``` | 28 | // ``` |
26 | pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
27 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | ||
28 | let block = ast::BlockExpr::cast(l_curly_token.parent())?; | ||
29 | let parent = block.syntax().parent()?; | ||
30 | let assist_id = AssistId("unwrap_block"); | 30 | let assist_id = AssistId("unwrap_block"); |
31 | let assist_label = "Unwrap block"; | 31 | let assist_label = "Unwrap block"; |
32 | 32 | ||
33 | let (expr, expr_to_unwrap) = match_ast! { | 33 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; |
34 | match parent { | 34 | let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; |
35 | ast::ForExpr(for_expr) => { | 35 | let mut parent = block.syntax().parent()?; |
36 | let block_expr = for_expr.loop_body()?; | 36 | if ast::MatchArm::can_cast(parent.kind()) { |
37 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | 37 | parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))? |
38 | (ast::Expr::ForExpr(for_expr), expr_to_unwrap) | 38 | } |
39 | }, | ||
40 | ast::WhileExpr(while_expr) => { | ||
41 | let block_expr = while_expr.loop_body()?; | ||
42 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | ||
43 | (ast::Expr::WhileExpr(while_expr), expr_to_unwrap) | ||
44 | }, | ||
45 | ast::LoopExpr(loop_expr) => { | ||
46 | let block_expr = loop_expr.loop_body()?; | ||
47 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | ||
48 | (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap) | ||
49 | }, | ||
50 | ast::IfExpr(if_expr) => { | ||
51 | let mut resp = None; | ||
52 | |||
53 | let then_branch = if_expr.then_branch()?; | ||
54 | if then_branch.l_curly_token()?.text_range().contains_range(ctx.frange.range) { | ||
55 | if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { | ||
56 | // For `else if` blocks | ||
57 | let ancestor_then_branch = ancestor.then_branch()?; | ||
58 | let l_curly_token = then_branch.l_curly_token()?; | ||
59 | |||
60 | let target = then_branch.syntax().text_range(); | ||
61 | return acc.add(assist_id, assist_label, target, |edit| { | ||
62 | let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | ||
63 | let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); | ||
64 | |||
65 | edit.delete(range_to_del_rest); | ||
66 | edit.delete(range_to_del_else_if); | ||
67 | edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); | ||
68 | }); | ||
69 | } else { | ||
70 | resp = Some((ast::Expr::IfExpr(if_expr.clone()), Expr::BlockExpr(then_branch))); | ||
71 | } | ||
72 | } else if let Some(else_branch) = if_expr.else_branch() { | ||
73 | match else_branch { | ||
74 | ElseBranch::Block(else_block) => { | ||
75 | let l_curly_token = else_block.l_curly_token()?; | ||
76 | if l_curly_token.text_range().contains_range(ctx.frange.range) { | ||
77 | let target = else_block.syntax().text_range(); | ||
78 | return acc.add(assist_id, assist_label, target, |edit| { | ||
79 | let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); | ||
80 | |||
81 | edit.delete(range_to_del); | ||
82 | edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); | ||
83 | }); | ||
84 | } | ||
85 | }, | ||
86 | ElseBranch::IfExpr(_) => {}, | ||
87 | } | ||
88 | } | ||
89 | 39 | ||
90 | resp? | 40 | let parent = ast::Expr::cast(parent)?; |
91 | }, | 41 | |
92 | _ => return None, | 42 | match parent.clone() { |
43 | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (), | ||
44 | ast::Expr::MatchExpr(_) => block = block.dedent(IndentLevel(1)), | ||
45 | ast::Expr::IfExpr(if_expr) => { | ||
46 | let then_branch = if_expr.then_branch()?; | ||
47 | if then_branch == block { | ||
48 | if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { | ||
49 | // For `else if` blocks | ||
50 | let ancestor_then_branch = ancestor.then_branch()?; | ||
51 | |||
52 | let target = then_branch.syntax().text_range(); | ||
53 | return acc.add(assist_id, assist_label, target, |edit| { | ||
54 | let range_to_del_else_if = TextRange::new( | ||
55 | ancestor_then_branch.syntax().text_range().end(), | ||
56 | l_curly_token.text_range().start(), | ||
57 | ); | ||
58 | let range_to_del_rest = TextRange::new( | ||
59 | then_branch.syntax().text_range().end(), | ||
60 | if_expr.syntax().text_range().end(), | ||
61 | ); | ||
62 | |||
63 | edit.delete(range_to_del_rest); | ||
64 | edit.delete(range_to_del_else_if); | ||
65 | edit.replace( | ||
66 | target, | ||
67 | update_expr_string(then_branch.to_string(), &[' ', '{']), | ||
68 | ); | ||
69 | }); | ||
70 | } | ||
71 | } else { | ||
72 | let target = block.syntax().text_range(); | ||
73 | return acc.add(assist_id, assist_label, target, |edit| { | ||
74 | let range_to_del = TextRange::new( | ||
75 | then_branch.syntax().text_range().end(), | ||
76 | l_curly_token.text_range().start(), | ||
77 | ); | ||
78 | |||
79 | edit.delete(range_to_del); | ||
80 | edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); | ||
81 | }); | ||
82 | } | ||
93 | } | 83 | } |
84 | _ => return None, | ||
94 | }; | 85 | }; |
95 | 86 | ||
96 | let target = expr_to_unwrap.syntax().text_range(); | 87 | let unwrapped = unwrap_trivial_block(block); |
97 | acc.add(assist_id, assist_label, target, |edit| { | 88 | let target = unwrapped.syntax().text_range(); |
98 | edit.replace( | 89 | acc.add(assist_id, assist_label, target, |builder| { |
99 | expr.syntax().text_range(), | 90 | builder.replace( |
100 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), | 91 | parent.syntax().text_range(), |
92 | update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), | ||
101 | ); | 93 | ); |
102 | }) | 94 | }) |
103 | } | 95 | } |
104 | 96 | ||
105 | fn extract_expr(cursor_range: TextRange, block: ast::BlockExpr) -> Option<ast::Expr> { | ||
106 | let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); | ||
107 | |||
108 | if cursor_in_range { | ||
109 | Some(unwrap_trivial_block(block)) | ||
110 | } else { | ||
111 | None | ||
112 | } | ||
113 | } | ||
114 | |||
115 | fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { | 97 | fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { |
116 | let expr_string = expr_str.trim_start_matches(trim_start_pat); | 98 | let expr_string = expr_str.trim_start_matches(trim_start_pat); |
117 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); | 99 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); |
@@ -490,6 +472,30 @@ mod tests { | |||
490 | } | 472 | } |
491 | 473 | ||
492 | #[test] | 474 | #[test] |
475 | fn unwrap_match_arm() { | ||
476 | check_assist( | ||
477 | unwrap_block, | ||
478 | r#" | ||
479 | fn main() { | ||
480 | match rel_path { | ||
481 | Ok(rel_path) => {<|> | ||
482 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
483 | Some((*id, rel_path)) | ||
484 | } | ||
485 | Err(_) => None, | ||
486 | } | ||
487 | } | ||
488 | "#, | ||
489 | r#" | ||
490 | fn main() { | ||
491 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
492 | Some((*id, rel_path)) | ||
493 | } | ||
494 | "#, | ||
495 | ); | ||
496 | } | ||
497 | |||
498 | #[test] | ||
493 | fn simple_if_in_while_bad_cursor_position() { | 499 | fn simple_if_in_while_bad_cursor_position() { |
494 | check_assist_not_applicable( | 500 | check_assist_not_applicable( |
495 | unwrap_block, | 501 | unwrap_block, |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index fb5d59a87..185428bd5 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -115,6 +115,7 @@ mod handlers { | |||
115 | mod change_return_type_to_result; | 115 | mod change_return_type_to_result; |
116 | mod change_visibility; | 116 | mod change_visibility; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod extract_struct_from_enum_variant; | ||
118 | mod fill_match_arms; | 119 | mod fill_match_arms; |
119 | mod fix_visibility; | 120 | mod fix_visibility; |
120 | mod flip_binexpr; | 121 | mod flip_binexpr; |
@@ -155,6 +156,7 @@ mod handlers { | |||
155 | change_return_type_to_result::change_return_type_to_result, | 156 | change_return_type_to_result::change_return_type_to_result, |
156 | change_visibility::change_visibility, | 157 | change_visibility::change_visibility, |
157 | early_return::convert_to_guarded_return, | 158 | early_return::convert_to_guarded_return, |
159 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | ||
158 | fill_match_arms::fill_match_arms, | 160 | fill_match_arms::fill_match_arms, |
159 | fix_visibility::fix_visibility, | 161 | fix_visibility::fix_visibility, |
160 | flip_binexpr::flip_binexpr, | 162 | flip_binexpr::flip_binexpr, |
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index d17504529..40a223727 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs | |||
@@ -338,6 +338,21 @@ fn main() { | |||
338 | } | 338 | } |
339 | 339 | ||
340 | #[test] | 340 | #[test] |
341 | fn doctest_extract_struct_from_enum_variant() { | ||
342 | check_doc_test( | ||
343 | "extract_struct_from_enum_variant", | ||
344 | r#####" | ||
345 | enum A { <|>One(u32, u32) } | ||
346 | "#####, | ||
347 | r#####" | ||
348 | struct One(pub u32, pub u32); | ||
349 | |||
350 | enum A { One(One) } | ||
351 | "#####, | ||
352 | ) | ||
353 | } | ||
354 | |||
355 | #[test] | ||
341 | fn doctest_fill_match_arms() { | 356 | fn doctest_fill_match_arms() { |
342 | check_doc_test( | 357 | check_doc_test( |
343 | "fill_match_arms", | 358 | "fill_match_arms", |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 4d2d3b48a..bf26048f2 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -15,12 +15,10 @@ use std::{ | |||
15 | 15 | ||
16 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
17 | use ra_syntax::SmolStr; | 17 | use ra_syntax::SmolStr; |
18 | use rustc_hash::FxHashMap; | 18 | use ra_tt::TokenExpander; |
19 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | 20 | ||
21 | use crate::{RelativePath, RelativePathBuf}; | 21 | use crate::{RelativePath, RelativePathBuf}; |
22 | use fmt::Display; | ||
23 | use ra_tt::TokenExpander; | ||
24 | 22 | ||
25 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 23 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
26 | /// messy and system-dependent, so most of the code should work directly with | 24 | /// messy and system-dependent, so most of the code should work directly with |
@@ -111,7 +109,7 @@ impl CrateName { | |||
111 | } | 109 | } |
112 | } | 110 | } |
113 | 111 | ||
114 | impl Display for CrateName { | 112 | impl fmt::Display for CrateName { |
115 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 113 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
116 | write!(f, "{}", self.0) | 114 | write!(f, "{}", self.0) |
117 | } | 115 | } |
@@ -337,15 +335,11 @@ impl Env { | |||
337 | } | 335 | } |
338 | 336 | ||
339 | impl ExternSource { | 337 | impl ExternSource { |
340 | pub fn extern_path(&self, path: impl AsRef<Path>) -> Option<(ExternSourceId, RelativePathBuf)> { | 338 | pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> { |
341 | let path = path.as_ref(); | ||
342 | self.extern_paths.iter().find_map(|(root_path, id)| { | 339 | self.extern_paths.iter().find_map(|(root_path, id)| { |
343 | if let Ok(rel_path) = path.strip_prefix(root_path) { | 340 | let rel_path = path.strip_prefix(root_path).ok()?; |
344 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | 341 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; |
345 | Some((*id, rel_path)) | 342 | Some((*id, rel_path)) |
346 | } else { | ||
347 | None | ||
348 | } | ||
349 | }) | 343 | }) |
350 | } | 344 | } |
351 | 345 | ||
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index fd4280de2..80ddb6058 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -7,12 +7,13 @@ use std::{panic, sync::Arc}; | |||
7 | 7 | ||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; | 9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; |
10 | use rustc_hash::FxHashSet; | ||
10 | 11 | ||
11 | pub use crate::{ | 12 | pub use crate::{ |
12 | cancellation::Canceled, | 13 | cancellation::Canceled, |
13 | input::{ | 14 | input::{ |
14 | CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, | 15 | CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, |
15 | FileId, ProcMacroId, SourceRoot, SourceRootId, | 16 | ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId, |
16 | }, | 17 | }, |
17 | }; | 18 | }; |
18 | pub use relative_path::{RelativePath, RelativePathBuf}; | 19 | pub use relative_path::{RelativePath, RelativePathBuf}; |
@@ -89,15 +90,13 @@ pub const DEFAULT_LRU_CAP: usize = 128; | |||
89 | pub trait FileLoader { | 90 | pub trait FileLoader { |
90 | /// Text of the file. | 91 | /// Text of the file. |
91 | fn file_text(&self, file_id: FileId) -> Arc<String>; | 92 | fn file_text(&self, file_id: FileId) -> Arc<String>; |
92 | fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) | 93 | /// Note that we intentionally accept a `&str` and not a `&Path` here. This |
93 | -> Option<FileId>; | 94 | /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, |
94 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; | 95 | /// so the input is guaranteed to be utf-8 string. We might introduce |
95 | 96 | /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we | |
96 | fn resolve_extern_path( | 97 | /// get by with a `&str` for the time being. |
97 | &self, | 98 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; |
98 | extern_id: ExternSourceId, | 99 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; |
99 | relative_path: &RelativePath, | ||
100 | ) -> Option<FileId>; | ||
101 | } | 100 | } |
102 | 101 | ||
103 | /// Database which stores all significant input facts: source code and project | 102 | /// Database which stores all significant input facts: source code and project |
@@ -135,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase { | |||
135 | #[salsa::input] | 134 | #[salsa::input] |
136 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; | 135 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; |
137 | 136 | ||
138 | fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>; | 137 | fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>; |
139 | } | 138 | } |
140 | 139 | ||
141 | fn source_root_crates( | 140 | fn source_root_crates( |
142 | db: &(impl SourceDatabaseExt + SourceDatabase), | 141 | db: &(impl SourceDatabaseExt + SourceDatabase), |
143 | id: SourceRootId, | 142 | id: SourceRootId, |
144 | ) -> Arc<Vec<CrateId>> { | 143 | ) -> Arc<FxHashSet<CrateId>> { |
145 | let root = db.source_root(id); | ||
146 | let graph = db.crate_graph(); | 144 | let graph = db.crate_graph(); |
147 | let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>(); | 145 | let res = graph |
146 | .iter() | ||
147 | .filter(|&krate| { | ||
148 | let root_file = graph[krate].root_file_id; | ||
149 | db.file_source_root(root_file) == id | ||
150 | }) | ||
151 | .collect::<FxHashSet<_>>(); | ||
148 | Arc::new(res) | 152 | Arc::new(res) |
149 | } | 153 | } |
150 | 154 | ||
@@ -155,33 +159,30 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
155 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 159 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
156 | SourceDatabaseExt::file_text(self.0, file_id) | 160 | SourceDatabaseExt::file_text(self.0, file_id) |
157 | } | 161 | } |
158 | fn resolve_relative_path( | 162 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
159 | &self, | 163 | // FIXME: this *somehow* should be platform agnostic... |
160 | anchor: FileId, | 164 | if std::path::Path::new(path).is_absolute() { |
161 | relative_path: &RelativePath, | 165 | let krate = *self.relevant_crates(anchor).iter().next()?; |
162 | ) -> Option<FileId> { | 166 | let (extern_source_id, relative_file) = |
163 | let path = { | 167 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; |
164 | let mut path = self.0.file_relative_path(anchor); | 168 | |
165 | assert!(path.pop()); | 169 | let source_root = self.0.source_root(SourceRootId(extern_source_id.0)); |
166 | path.push(relative_path); | 170 | source_root.file_by_relative_path(&relative_file) |
167 | path.normalize() | 171 | } else { |
168 | }; | 172 | let rel_path = { |
169 | let source_root = self.0.file_source_root(anchor); | 173 | let mut rel_path = self.0.file_relative_path(anchor); |
170 | let source_root = self.0.source_root(source_root); | 174 | assert!(rel_path.pop()); |
171 | source_root.file_by_relative_path(&path) | 175 | rel_path.push(path); |
176 | rel_path.normalize() | ||
177 | }; | ||
178 | let source_root = self.0.file_source_root(anchor); | ||
179 | let source_root = self.0.source_root(source_root); | ||
180 | source_root.file_by_relative_path(&rel_path) | ||
181 | } | ||
172 | } | 182 | } |
173 | 183 | ||
174 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 184 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
175 | let source_root = self.0.file_source_root(file_id); | 185 | let source_root = self.0.file_source_root(file_id); |
176 | self.0.source_root_crates(source_root) | 186 | self.0.source_root_crates(source_root) |
177 | } | 187 | } |
178 | |||
179 | fn resolve_extern_path( | ||
180 | &self, | ||
181 | extern_id: ExternSourceId, | ||
182 | relative_path: &RelativePath, | ||
183 | ) -> Option<FileId> { | ||
184 | let source_root = self.0.source_root(SourceRootId(extern_id.0)); | ||
185 | source_root.file_by_relative_path(&relative_path) | ||
186 | } | ||
187 | } | 188 | } |
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 041e38a9f..6c4170529 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs | |||
@@ -18,8 +18,17 @@ pub use cargo_metadata::diagnostic::{ | |||
18 | 18 | ||
19 | #[derive(Clone, Debug, PartialEq, Eq)] | 19 | #[derive(Clone, Debug, PartialEq, Eq)] |
20 | pub enum FlycheckConfig { | 20 | pub enum FlycheckConfig { |
21 | CargoCommand { command: String, all_targets: bool, all_features: bool, extra_args: Vec<String> }, | 21 | CargoCommand { |
22 | CustomCommand { command: String, args: Vec<String> }, | 22 | command: String, |
23 | all_targets: bool, | ||
24 | all_features: bool, | ||
25 | features: Vec<String>, | ||
26 | extra_args: Vec<String>, | ||
27 | }, | ||
28 | CustomCommand { | ||
29 | command: String, | ||
30 | args: Vec<String>, | ||
31 | }, | ||
23 | } | 32 | } |
24 | 33 | ||
25 | /// Flycheck wraps the shared state and communication machinery used for | 34 | /// Flycheck wraps the shared state and communication machinery used for |
@@ -188,7 +197,13 @@ impl FlycheckThread { | |||
188 | self.check_process = None; | 197 | self.check_process = None; |
189 | 198 | ||
190 | let mut cmd = match &self.config { | 199 | let mut cmd = match &self.config { |
191 | FlycheckConfig::CargoCommand { command, all_targets, all_features, extra_args } => { | 200 | FlycheckConfig::CargoCommand { |
201 | command, | ||
202 | all_targets, | ||
203 | all_features, | ||
204 | extra_args, | ||
205 | features, | ||
206 | } => { | ||
192 | let mut cmd = Command::new(ra_toolchain::cargo()); | 207 | let mut cmd = Command::new(ra_toolchain::cargo()); |
193 | cmd.arg(command); | 208 | cmd.arg(command); |
194 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) | 209 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) |
@@ -198,6 +213,9 @@ impl FlycheckThread { | |||
198 | } | 213 | } |
199 | if *all_features { | 214 | if *all_features { |
200 | cmd.arg("--all-features"); | 215 | cmd.arg("--all-features"); |
216 | } else if !features.is_empty() { | ||
217 | cmd.arg("--features"); | ||
218 | cmd.arg(features.join(" ")); | ||
201 | } | 219 | } |
202 | cmd.args(extra_args); | 220 | cmd.args(extra_args); |
203 | cmd | 221 | cmd |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e40aeffbc..1a9f6cc76 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -9,6 +9,7 @@ use hir_def::{ | |||
9 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
10 | docs::Documentation, | 10 | docs::Documentation, |
11 | expr::{BindingAnnotation, Pat, PatId}, | 11 | expr::{BindingAnnotation, Pat, PatId}, |
12 | import_map, | ||
12 | per_ns::PerNs, | 13 | per_ns::PerNs, |
13 | resolver::{HasResolver, Resolver}, | 14 | resolver::{HasResolver, Resolver}, |
14 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
@@ -98,6 +99,23 @@ impl Crate { | |||
98 | db.crate_graph()[self.id].display_name.as_ref().cloned() | 99 | db.crate_graph()[self.id].display_name.as_ref().cloned() |
99 | } | 100 | } |
100 | 101 | ||
102 | pub fn query_external_importables( | ||
103 | self, | ||
104 | db: &dyn DefDatabase, | ||
105 | query: &str, | ||
106 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
107 | import_map::search_dependencies( | ||
108 | db, | ||
109 | self.into(), | ||
110 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), | ||
111 | ) | ||
112 | .into_iter() | ||
113 | .map(|item| match item { | ||
114 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
115 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
116 | }) | ||
117 | } | ||
118 | |||
101 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | 119 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { |
102 | db.crate_graph().iter().map(|id| Crate { id }).collect() | 120 | db.crate_graph().iter().map(|id| Crate { id }).collect() |
103 | } | 121 | } |
@@ -637,6 +655,10 @@ impl Function { | |||
637 | db.function_data(self.id).params.clone() | 655 | db.function_data(self.id).params.clone() |
638 | } | 656 | } |
639 | 657 | ||
658 | pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { | ||
659 | db.function_data(self.id).is_unsafe | ||
660 | } | ||
661 | |||
640 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 662 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { |
641 | let _p = profile("Function::diagnostics"); | 663 | let _p = profile("Function::diagnostics"); |
642 | let infer = db.infer(self.id.into()); | 664 | let infer = db.infer(self.id.into()); |
@@ -1190,6 +1212,10 @@ impl Type { | |||
1190 | ) | 1212 | ) |
1191 | } | 1213 | } |
1192 | 1214 | ||
1215 | pub fn is_raw_ptr(&self) -> bool { | ||
1216 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) | ||
1217 | } | ||
1218 | |||
1193 | pub fn contains_unknown(&self) -> bool { | 1219 | pub fn contains_unknown(&self) -> bool { |
1194 | return go(&self.ty.value); | 1220 | return go(&self.ty.value); |
1195 | 1221 | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index ec931b34f..b6b665de1 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -3,11 +3,11 @@ | |||
3 | pub use hir_def::db::{ | 3 | pub use hir_def::db::{ |
4 | AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, | 4 | AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, |
5 | CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, | 5 | CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, |
6 | ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternConstQuery, | 6 | ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, |
7 | InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, | 7 | InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, |
8 | InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, | 8 | InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, |
9 | LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery, | 9 | InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, |
10 | TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, | 10 | StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, |
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, | 13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, |
@@ -18,8 +18,8 @@ pub use hir_ty::db::{ | |||
18 | GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, | 18 | GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, |
19 | HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, | 19 | HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, |
20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, | 20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, |
21 | InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery, | 21 | InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, |
22 | TraitSolveQuery, TyQuery, ValueTyQuery, | 22 | TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | #[test] | 25 | #[test] |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 7c1f79f27..a232a5856 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
122 | let macro_call = | 122 | let macro_call = |
123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | 123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); |
124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
125 | let krate = sa.resolver.krate()?; | ||
125 | let macro_call_id = macro_call | 126 | let macro_call_id = macro_call |
126 | .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | 127 | .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; |
127 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | 128 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) |
128 | } | 129 | } |
129 | 130 | ||
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4b509f07c..7c6bbea13 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -307,7 +307,8 @@ impl SourceAnalyzer { | |||
307 | db: &dyn HirDatabase, | 307 | db: &dyn HirDatabase, |
308 | macro_call: InFile<&ast::MacroCall>, | 308 | macro_call: InFile<&ast::MacroCall>, |
309 | ) -> Option<HirFileId> { | 309 | ) -> Option<HirFileId> { |
310 | let macro_call_id = macro_call.as_call_id(db.upcast(), |path| { | 310 | let krate = self.resolver.krate()?; |
311 | let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { | ||
311 | self.resolver.resolve_path_as_macro(db.upcast(), &path) | 312 | self.resolver.resolve_path_as_macro(db.upcast(), &path) |
312 | })?; | 313 | })?; |
313 | Some(macro_call_id.as_file()) | 314 | Some(macro_call_id.as_file()) |
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index b85358308..ef1f65ee0 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml | |||
@@ -14,6 +14,9 @@ rustc-hash = "1.1.0" | |||
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | anymap = "0.12.1" | 15 | anymap = "0.12.1" |
16 | drop_bomb = "0.1.4" | 16 | drop_bomb = "0.1.4" |
17 | fst = { version = "0.4", default-features = false } | ||
18 | itertools = "0.9.0" | ||
19 | indexmap = "1.4.0" | ||
17 | 20 | ||
18 | stdx = { path = "../stdx" } | 21 | stdx = { path = "../stdx" } |
19 | 22 | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 8b6c0bede..2eeba0572 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -87,12 +87,18 @@ impl Attrs { | |||
87 | } | 87 | } |
88 | 88 | ||
89 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { | 89 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { |
90 | let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( | ||
91 | |docs_text| Attr { | ||
92 | input: Some(AttrInput::Literal(SmolStr::new(docs_text))), | ||
93 | path: ModPath::from(hir_expand::name!(doc)), | ||
94 | }, | ||
95 | ); | ||
90 | let mut attrs = owner.attrs().peekable(); | 96 | let mut attrs = owner.attrs().peekable(); |
91 | let entries = if attrs.peek().is_none() { | 97 | let entries = if attrs.peek().is_none() { |
92 | // Avoid heap allocation | 98 | // Avoid heap allocation |
93 | None | 99 | None |
94 | } else { | 100 | } else { |
95 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) | 101 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) |
96 | }; | 102 | }; |
97 | Attrs { entries } | 103 | Attrs { entries } |
98 | } | 104 | } |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 273036cee..4f2350915 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -97,7 +97,7 @@ impl Expander { | |||
97 | 97 | ||
98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
99 | 99 | ||
100 | if let Some(call_id) = macro_call.as_call_id(db, |path| { | 100 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { |
101 | if let Some(local_scope) = local_scope { | 101 | if let Some(local_scope) = local_scope { |
102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { | 102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
103 | return Some(def); | 103 | return Some(def); |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index e2130d931..53599e74a 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -34,6 +34,7 @@ pub struct FunctionData { | |||
34 | /// True if the first param is `self`. This is relevant to decide whether this | 34 | /// True if the first param is `self`. This is relevant to decide whether this |
35 | /// can be called as a method. | 35 | /// can be called as a method. |
36 | pub has_self_param: bool, | 36 | pub has_self_param: bool, |
37 | pub is_unsafe: bool, | ||
37 | pub visibility: RawVisibility, | 38 | pub visibility: RawVisibility, |
38 | } | 39 | } |
39 | 40 | ||
@@ -85,17 +86,20 @@ impl FunctionData { | |||
85 | ret_type | 86 | ret_type |
86 | }; | 87 | }; |
87 | 88 | ||
89 | let is_unsafe = src.value.unsafe_token().is_some(); | ||
90 | |||
88 | let vis_default = RawVisibility::default_for_container(loc.container); | 91 | let vis_default = RawVisibility::default_for_container(loc.container); |
89 | let visibility = | 92 | let visibility = |
90 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | 93 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); |
91 | 94 | ||
92 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs }; | 95 | let sig = |
96 | FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; | ||
93 | Arc::new(sig) | 97 | Arc::new(sig) |
94 | } | 98 | } |
95 | } | 99 | } |
96 | 100 | ||
97 | fn desugar_future_path(orig: TypeRef) -> Path { | 101 | fn desugar_future_path(orig: TypeRef) -> Path { |
98 | let path = path![std::future::Future]; | 102 | let path = path![core::future::Future]; |
99 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | 103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); |
100 | let mut last = GenericArgs::empty(); | 104 | let mut last = GenericArgs::empty(); |
101 | last.bindings.push(AssociatedTypeBinding { | 105 | last.bindings.push(AssociatedTypeBinding { |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 945a0025e..10cc26480 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Defines database & queries for name resolution. | 1 | //! Defines database & queries for name resolution. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use hir_expand::{db::AstDatabase, name::Name, HirFileId}; | 4 | use hir_expand::{db::AstDatabase, HirFileId}; |
5 | use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; | 5 | use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; |
6 | use ra_prof::profile; | 6 | use ra_prof::profile; |
7 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
@@ -12,13 +12,10 @@ use crate::{ | |||
12 | body::{scope::ExprScopes, Body, BodySourceMap}, | 12 | body::{scope::ExprScopes, Body, BodySourceMap}, |
13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, | 13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, |
14 | docs::Documentation, | 14 | docs::Documentation, |
15 | find_path, | ||
16 | generics::GenericParams, | 15 | generics::GenericParams, |
17 | item_scope::ItemInNs, | 16 | import_map::ImportMap, |
18 | lang_item::{LangItemTarget, LangItems}, | 17 | lang_item::{LangItemTarget, LangItems}, |
19 | nameres::{raw::RawItems, CrateDefMap}, | 18 | nameres::{raw::RawItems, CrateDefMap}, |
20 | path::ModPath, | ||
21 | visibility::Visibility, | ||
22 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
23 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 20 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
24 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 21 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, |
@@ -113,15 +110,8 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
113 | #[salsa::invoke(Documentation::documentation_query)] | 110 | #[salsa::invoke(Documentation::documentation_query)] |
114 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; | 111 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; |
115 | 112 | ||
116 | #[salsa::invoke(find_path::importable_locations_of_query)] | 113 | #[salsa::invoke(ImportMap::import_map_query)] |
117 | fn importable_locations_of( | 114 | fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; |
118 | &self, | ||
119 | item: ItemInNs, | ||
120 | krate: CrateId, | ||
121 | ) -> Arc<[(ModuleId, Name, Visibility)]>; | ||
122 | |||
123 | #[salsa::invoke(find_path::find_path_inner_query)] | ||
124 | fn find_path_inner(&self, item: ItemInNs, from: ModuleId, max_len: usize) -> Option<ModPath>; | ||
125 | } | 115 | } |
126 | 116 | ||
127 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 117 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { |
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index b221ae1ce..2630b3d89 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs | |||
@@ -29,6 +29,13 @@ impl Documentation { | |||
29 | Documentation(s.into()) | 29 | Documentation(s.into()) |
30 | } | 30 | } |
31 | 31 | ||
32 | pub fn from_ast<N>(node: &N) -> Option<Documentation> | ||
33 | where | ||
34 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
35 | { | ||
36 | docs_from_ast(node) | ||
37 | } | ||
38 | |||
32 | pub fn as_str(&self) -> &str { | 39 | pub fn as_str(&self) -> &str { |
33 | &*self.0 | 40 | &*self.0 |
34 | } | 41 | } |
@@ -70,6 +77,45 @@ impl Documentation { | |||
70 | } | 77 | } |
71 | } | 78 | } |
72 | 79 | ||
73 | pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> { | 80 | pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation> |
74 | node.doc_comment_text().map(|it| Documentation::new(&it)) | 81 | where |
82 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
83 | { | ||
84 | let doc_comment_text = node.doc_comment_text(); | ||
85 | let doc_attr_text = expand_doc_attrs(node); | ||
86 | let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); | ||
87 | docs.map(|it| Documentation::new(&it)) | ||
88 | } | ||
89 | |||
90 | fn merge_doc_comments_and_attrs( | ||
91 | doc_comment_text: Option<String>, | ||
92 | doc_attr_text: Option<String>, | ||
93 | ) -> Option<String> { | ||
94 | match (doc_comment_text, doc_attr_text) { | ||
95 | (Some(mut comment_text), Some(attr_text)) => { | ||
96 | comment_text.push_str("\n\n"); | ||
97 | comment_text.push_str(&attr_text); | ||
98 | Some(comment_text) | ||
99 | } | ||
100 | (Some(comment_text), None) => Some(comment_text), | ||
101 | (None, Some(attr_text)) => Some(attr_text), | ||
102 | (None, None) => None, | ||
103 | } | ||
104 | } | ||
105 | |||
106 | fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { | ||
107 | let mut docs = String::new(); | ||
108 | for attr in owner.attrs() { | ||
109 | if let Some(("doc", value)) = | ||
110 | attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) | ||
111 | { | ||
112 | docs.push_str(value); | ||
113 | docs.push_str("\n\n"); | ||
114 | } | ||
115 | } | ||
116 | if docs.is_empty() { | ||
117 | None | ||
118 | } else { | ||
119 | Some(docs.trim_end_matches("\n\n").to_owned()) | ||
120 | } | ||
75 | } | 121 | } |
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 4db798473..06701a830 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -1,9 +1,8 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | 1 | //! An algorithm to find a path to refer to a certain item. |
2 | 2 | ||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_expand::name::{known, AsName, Name}; | 3 | use hir_expand::name::{known, AsName, Name}; |
6 | use ra_prof::profile; | 4 | use ra_prof::profile; |
5 | use rustc_hash::FxHashSet; | ||
7 | use test_utils::mark; | 6 | use test_utils::mark; |
8 | 7 | ||
9 | use crate::{ | 8 | use crate::{ |
@@ -11,7 +10,7 @@ use crate::{ | |||
11 | item_scope::ItemInNs, | 10 | item_scope::ItemInNs, |
12 | path::{ModPath, PathKind}, | 11 | path::{ModPath, PathKind}, |
13 | visibility::Visibility, | 12 | visibility::Visibility, |
14 | CrateId, ModuleDefId, ModuleId, | 13 | ModuleDefId, ModuleId, |
15 | }; | 14 | }; |
16 | 15 | ||
17 | // FIXME: handle local items | 16 | // FIXME: handle local items |
@@ -20,7 +19,7 @@ use crate::{ | |||
20 | /// *from where* you're referring to the item, hence the `from` parameter. | 19 | /// *from where* you're referring to the item, hence the `from` parameter. |
21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 20 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
22 | let _p = profile("find_path"); | 21 | let _p = profile("find_path"); |
23 | db.find_path_inner(item, from, MAX_PATH_LEN) | 22 | find_path_inner(db, item, from, MAX_PATH_LEN) |
24 | } | 23 | } |
25 | 24 | ||
26 | const MAX_PATH_LEN: usize = 15; | 25 | const MAX_PATH_LEN: usize = 15; |
@@ -36,20 +35,9 @@ impl ModPath { | |||
36 | let first_segment = self.segments.first(); | 35 | let first_segment = self.segments.first(); |
37 | first_segment == Some(&known::alloc) || first_segment == Some(&known::core) | 36 | first_segment == Some(&known::alloc) || first_segment == Some(&known::core) |
38 | } | 37 | } |
39 | |||
40 | fn len(&self) -> usize { | ||
41 | self.segments.len() | ||
42 | + match self.kind { | ||
43 | PathKind::Plain => 0, | ||
44 | PathKind::Super(i) => i as usize, | ||
45 | PathKind::Crate => 1, | ||
46 | PathKind::Abs => 0, | ||
47 | PathKind::DollarCrate(_) => 1, | ||
48 | } | ||
49 | } | ||
50 | } | 38 | } |
51 | 39 | ||
52 | pub(crate) fn find_path_inner_query( | 40 | fn find_path_inner( |
53 | db: &dyn DefDatabase, | 41 | db: &dyn DefDatabase, |
54 | item: ItemInNs, | 42 | item: ItemInNs, |
55 | from: ModuleId, | 43 | from: ModuleId, |
@@ -133,31 +121,67 @@ pub(crate) fn find_path_inner_query( | |||
133 | } | 121 | } |
134 | 122 | ||
135 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | 123 | // - otherwise, look for modules containing (reexporting) it and import it from one of those |
124 | |||
136 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; | 125 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; |
137 | let crate_attrs = db.attrs(crate_root.into()); | 126 | let crate_attrs = db.attrs(crate_root.into()); |
138 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | 127 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); |
139 | let importable_locations = find_importable_locations(db, item, from); | ||
140 | let mut best_path = None; | 128 | let mut best_path = None; |
141 | let mut best_path_len = max_len; | 129 | let mut best_path_len = max_len; |
142 | for (module_id, name) in importable_locations { | ||
143 | let mut path = match db.find_path_inner( | ||
144 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | ||
145 | from, | ||
146 | best_path_len - 1, | ||
147 | ) { | ||
148 | None => continue, | ||
149 | Some(path) => path, | ||
150 | }; | ||
151 | path.segments.push(name); | ||
152 | 130 | ||
153 | let new_path = if let Some(best_path) = best_path { | 131 | if item.krate(db) == Some(from.krate) { |
154 | select_best_path(best_path, path, prefer_no_std) | 132 | // Item was defined in the same crate that wants to import it. It cannot be found in any |
155 | } else { | 133 | // dependency in this case. |
156 | path | 134 | |
157 | }; | 135 | let local_imports = find_local_import_locations(db, item, from); |
158 | best_path_len = new_path.len(); | 136 | for (module_id, name) in local_imports { |
159 | best_path = Some(new_path); | 137 | if let Some(mut path) = find_path_inner( |
138 | db, | ||
139 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | ||
140 | from, | ||
141 | best_path_len - 1, | ||
142 | ) { | ||
143 | path.segments.push(name); | ||
144 | |||
145 | let new_path = if let Some(best_path) = best_path { | ||
146 | select_best_path(best_path, path, prefer_no_std) | ||
147 | } else { | ||
148 | path | ||
149 | }; | ||
150 | best_path_len = new_path.len(); | ||
151 | best_path = Some(new_path); | ||
152 | } | ||
153 | } | ||
154 | } else { | ||
155 | // Item was defined in some upstream crate. This means that it must be exported from one, | ||
156 | // too (unless we can't name it at all). It could *also* be (re)exported by the same crate | ||
157 | // that wants to import it here, but we always prefer to use the external path here. | ||
158 | |||
159 | let crate_graph = db.crate_graph(); | ||
160 | let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { | ||
161 | let import_map = db.import_map(dep.crate_id); | ||
162 | import_map.import_info_for(item).and_then(|info| { | ||
163 | // Determine best path for containing module and append last segment from `info`. | ||
164 | let mut path = find_path_inner( | ||
165 | db, | ||
166 | ItemInNs::Types(ModuleDefId::ModuleId(info.container)), | ||
167 | from, | ||
168 | best_path_len - 1, | ||
169 | )?; | ||
170 | path.segments.push(info.path.segments.last().unwrap().clone()); | ||
171 | Some(path) | ||
172 | }) | ||
173 | }); | ||
174 | |||
175 | for path in extern_paths { | ||
176 | let new_path = if let Some(best_path) = best_path { | ||
177 | select_best_path(best_path, path, prefer_no_std) | ||
178 | } else { | ||
179 | path | ||
180 | }; | ||
181 | best_path = Some(new_path); | ||
182 | } | ||
160 | } | 183 | } |
184 | |||
161 | best_path | 185 | best_path |
162 | } | 186 | } |
163 | 187 | ||
@@ -185,69 +209,86 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) - | |||
185 | } | 209 | } |
186 | } | 210 | } |
187 | 211 | ||
188 | fn find_importable_locations( | 212 | /// Finds locations in `from.krate` from which `item` can be imported by `from`. |
213 | fn find_local_import_locations( | ||
189 | db: &dyn DefDatabase, | 214 | db: &dyn DefDatabase, |
190 | item: ItemInNs, | 215 | item: ItemInNs, |
191 | from: ModuleId, | 216 | from: ModuleId, |
192 | ) -> Vec<(ModuleId, Name)> { | 217 | ) -> Vec<(ModuleId, Name)> { |
193 | let crate_graph = db.crate_graph(); | 218 | let _p = profile("find_local_import_locations"); |
194 | let mut result = Vec::new(); | 219 | |
195 | // We only look in the crate from which we are importing, and the direct | 220 | // `from` can import anything below `from` with visibility of at least `from`, and anything |
196 | // dependencies. We cannot refer to names from transitive dependencies | 221 | // above `from` with any visibility. That means we do not need to descend into private siblings |
197 | // directly (only through reexports in direct dependencies). | 222 | // of `from` (and similar). |
198 | for krate in Some(from.krate) | 223 | |
199 | .into_iter() | 224 | let def_map = db.crate_def_map(from.krate); |
200 | .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) | 225 | |
201 | { | 226 | // Compute the initial worklist. We start with all direct child modules of `from` as well as all |
202 | result.extend( | 227 | // of its (recursive) parent modules. |
203 | db.importable_locations_of(item, krate) | 228 | let data = &def_map.modules[from.local_id]; |
204 | .iter() | 229 | let mut worklist = data |
205 | .filter(|(_, _, vis)| vis.is_visible_from(db, from)) | 230 | .children |
206 | .map(|(m, n, _)| (*m, n.clone())), | 231 | .values() |
207 | ); | 232 | .map(|child| ModuleId { krate: from.krate, local_id: *child }) |
208 | } | 233 | .collect::<Vec<_>>(); |
209 | result | 234 | let mut parent = data.parent; |
210 | } | 235 | while let Some(p) = parent { |
236 | worklist.push(ModuleId { krate: from.krate, local_id: p }); | ||
237 | parent = def_map.modules[p].parent; | ||
238 | } | ||
239 | |||
240 | let mut seen: FxHashSet<_> = FxHashSet::default(); | ||
241 | |||
242 | let mut locations = Vec::new(); | ||
243 | while let Some(module) = worklist.pop() { | ||
244 | if !seen.insert(module) { | ||
245 | continue; // already processed this module | ||
246 | } | ||
247 | |||
248 | let ext_def_map; | ||
249 | let data = if module.krate == from.krate { | ||
250 | &def_map[module.local_id] | ||
251 | } else { | ||
252 | // The crate might reexport a module defined in another crate. | ||
253 | ext_def_map = db.crate_def_map(module.krate); | ||
254 | &ext_def_map[module.local_id] | ||
255 | }; | ||
211 | 256 | ||
212 | /// Collects all locations from which we might import the item in a particular | ||
213 | /// crate. These include the original definition of the item, and any | ||
214 | /// non-private `use`s. | ||
215 | /// | ||
216 | /// Note that the crate doesn't need to be the one in which the item is defined; | ||
217 | /// it might be re-exported in other crates. | ||
218 | pub(crate) fn importable_locations_of_query( | ||
219 | db: &dyn DefDatabase, | ||
220 | item: ItemInNs, | ||
221 | krate: CrateId, | ||
222 | ) -> Arc<[(ModuleId, Name, Visibility)]> { | ||
223 | let _p = profile("importable_locations_of_query"); | ||
224 | let def_map = db.crate_def_map(krate); | ||
225 | let mut result = Vec::new(); | ||
226 | for (local_id, data) in def_map.modules.iter() { | ||
227 | if let Some((name, vis)) = data.scope.name_of(item) { | 257 | if let Some((name, vis)) = data.scope.name_of(item) { |
228 | let is_private = if let Visibility::Module(private_to) = vis { | 258 | if vis.is_visible_from(db, from) { |
229 | private_to.local_id == local_id | 259 | let is_private = if let Visibility::Module(private_to) = vis { |
230 | } else { | 260 | private_to.local_id == module.local_id |
231 | false | 261 | } else { |
232 | }; | 262 | false |
233 | let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { | 263 | }; |
234 | data.scope.declarations().any(|it| it == module_def_id) | 264 | let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { |
235 | } else { | 265 | data.scope.declarations().any(|it| it == module_def_id) |
236 | false | 266 | } else { |
237 | }; | 267 | false |
238 | if is_private && !is_original_def { | 268 | }; |
269 | |||
239 | // Ignore private imports. these could be used if we are | 270 | // Ignore private imports. these could be used if we are |
240 | // in a submodule of this module, but that's usually not | 271 | // in a submodule of this module, but that's usually not |
241 | // what the user wants; and if this module can import | 272 | // what the user wants; and if this module can import |
242 | // the item and we're a submodule of it, so can we. | 273 | // the item and we're a submodule of it, so can we. |
243 | // Also this keeps the cached data smaller. | 274 | // Also this keeps the cached data smaller. |
244 | continue; | 275 | if !is_private || is_original_def { |
276 | locations.push((module, name.clone())); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | // Descend into all modules visible from `from`. | ||
282 | for (_, per_ns) in data.scope.entries() { | ||
283 | if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() { | ||
284 | if vis.is_visible_from(db, from) { | ||
285 | worklist.push(module); | ||
286 | } | ||
245 | } | 287 | } |
246 | result.push((ModuleId { krate, local_id }, name.clone(), vis)); | ||
247 | } | 288 | } |
248 | } | 289 | } |
249 | 290 | ||
250 | Arc::from(result) | 291 | locations |
251 | } | 292 | } |
252 | 293 | ||
253 | #[cfg(test)] | 294 | #[cfg(test)] |
@@ -264,8 +305,8 @@ mod tests { | |||
264 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | 305 | /// `code` needs to contain a cursor marker; checks that `find_path` for the |
265 | /// item the `path` refers to returns that same path when called from the | 306 | /// item the `path` refers to returns that same path when called from the |
266 | /// module the cursor is in. | 307 | /// module the cursor is in. |
267 | fn check_found_path(code: &str, path: &str) { | 308 | fn check_found_path(ra_fixture: &str, path: &str) { |
268 | let (db, pos) = TestDB::with_position(code); | 309 | let (db, pos) = TestDB::with_position(ra_fixture); |
269 | let module = db.module_for_file(pos.file_id); | 310 | let module = db.module_for_file(pos.file_id); |
270 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); | 311 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); |
271 | let ast_path = parsed_path_file | 312 | let ast_path = parsed_path_file |
@@ -396,6 +437,44 @@ mod tests { | |||
396 | } | 437 | } |
397 | 438 | ||
398 | #[test] | 439 | #[test] |
440 | fn partially_imported() { | ||
441 | // Tests that short paths are used even for external items, when parts of the path are | ||
442 | // already in scope. | ||
443 | check_found_path( | ||
444 | r#" | ||
445 | //- /main.rs crate:main deps:ra_syntax | ||
446 | |||
447 | use ra_syntax::ast; | ||
448 | <|> | ||
449 | |||
450 | //- /lib.rs crate:ra_syntax | ||
451 | pub mod ast { | ||
452 | pub enum ModuleItem { | ||
453 | A, B, C, | ||
454 | } | ||
455 | } | ||
456 | "#, | ||
457 | "ast::ModuleItem", | ||
458 | ); | ||
459 | |||
460 | check_found_path( | ||
461 | r#" | ||
462 | //- /main.rs crate:main deps:ra_syntax | ||
463 | |||
464 | <|> | ||
465 | |||
466 | //- /lib.rs crate:ra_syntax | ||
467 | pub mod ast { | ||
468 | pub enum ModuleItem { | ||
469 | A, B, C, | ||
470 | } | ||
471 | } | ||
472 | "#, | ||
473 | "ra_syntax::ast::ModuleItem", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
399 | fn same_crate_reexport() { | 478 | fn same_crate_reexport() { |
400 | let code = r#" | 479 | let code = r#" |
401 | //- /main.rs | 480 | //- /main.rs |
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs new file mode 100644 index 000000000..68e20d06b --- /dev/null +++ b/crates/ra_hir_def/src/import_map.rs | |||
@@ -0,0 +1,679 @@ | |||
1 | //! A map of all publicly exported items in a crate. | ||
2 | |||
3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; | ||
4 | |||
5 | use fst::{self, Streamer}; | ||
6 | use indexmap::{map::Entry, IndexMap}; | ||
7 | use ra_db::CrateId; | ||
8 | use rustc_hash::FxHasher; | ||
9 | |||
10 | use crate::{ | ||
11 | db::DefDatabase, | ||
12 | item_scope::ItemInNs, | ||
13 | path::{ModPath, PathKind}, | ||
14 | visibility::Visibility, | ||
15 | ModuleDefId, ModuleId, | ||
16 | }; | ||
17 | |||
18 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; | ||
19 | |||
20 | /// Item import details stored in the `ImportMap`. | ||
21 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
22 | pub struct ImportInfo { | ||
23 | /// A path that can be used to import the item, relative to the crate's root. | ||
24 | pub path: ModPath, | ||
25 | /// The module containing this item. | ||
26 | pub container: ModuleId, | ||
27 | } | ||
28 | |||
29 | /// A map from publicly exported items to the path needed to import/name them from a downstream | ||
30 | /// crate. | ||
31 | /// | ||
32 | /// Reexports of items are taken into account, ie. if something is exported under multiple | ||
33 | /// names, the one with the shortest import path will be used. | ||
34 | /// | ||
35 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs | ||
36 | /// to be prepended to the `ModPath` before the path is valid. | ||
37 | pub struct ImportMap { | ||
38 | map: FxIndexMap<ItemInNs, ImportInfo>, | ||
39 | |||
40 | /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the | ||
41 | /// values returned by running `fst`. | ||
42 | /// | ||
43 | /// Since a path can refer to multiple items due to namespacing, we store all items with the | ||
44 | /// same path right after each other. This allows us to find all items after the FST gives us | ||
45 | /// the index of the first one. | ||
46 | importables: Vec<ItemInNs>, | ||
47 | fst: fst::Map<Vec<u8>>, | ||
48 | } | ||
49 | |||
50 | impl ImportMap { | ||
51 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | ||
52 | let _p = ra_prof::profile("import_map_query"); | ||
53 | let def_map = db.crate_def_map(krate); | ||
54 | let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); | ||
55 | |||
56 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
57 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; | ||
58 | let root = ModuleId { krate, local_id: def_map.root }; | ||
59 | let mut worklist = vec![(root, empty)]; | ||
60 | while let Some((module, mod_path)) = worklist.pop() { | ||
61 | let ext_def_map; | ||
62 | let mod_data = if module.krate == krate { | ||
63 | &def_map[module.local_id] | ||
64 | } else { | ||
65 | // The crate might reexport a module defined in another crate. | ||
66 | ext_def_map = db.crate_def_map(module.krate); | ||
67 | &ext_def_map[module.local_id] | ||
68 | }; | ||
69 | |||
70 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
71 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
72 | if per_ns.is_none() { | ||
73 | None | ||
74 | } else { | ||
75 | Some((name, per_ns)) | ||
76 | } | ||
77 | }); | ||
78 | |||
79 | for (name, per_ns) in visible_items { | ||
80 | let mk_path = || { | ||
81 | let mut path = mod_path.clone(); | ||
82 | path.segments.push(name.clone()); | ||
83 | path | ||
84 | }; | ||
85 | |||
86 | for item in per_ns.iter_items() { | ||
87 | let path = mk_path(); | ||
88 | match import_map.entry(item) { | ||
89 | Entry::Vacant(entry) => { | ||
90 | entry.insert(ImportInfo { path, container: module }); | ||
91 | } | ||
92 | Entry::Occupied(mut entry) => { | ||
93 | // If the new path is shorter, prefer that one. | ||
94 | if path.len() < entry.get().path.len() { | ||
95 | *entry.get_mut() = ImportInfo { path, container: module }; | ||
96 | } else { | ||
97 | continue; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // If we've just added a path to a module, descend into it. We might traverse | ||
103 | // modules multiple times, but only if the new path to it is shorter than the | ||
104 | // first (else we `continue` above). | ||
105 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
106 | worklist.push((mod_id, mk_path())); | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | let mut importables = import_map.iter().collect::<Vec<_>>(); | ||
113 | |||
114 | importables.sort_by(cmp); | ||
115 | |||
116 | // Build the FST, taking care not to insert duplicate values. | ||
117 | |||
118 | let mut builder = fst::MapBuilder::memory(); | ||
119 | let mut last_batch_start = 0; | ||
120 | |||
121 | for idx in 0..importables.len() { | ||
122 | if let Some(next_item) = importables.get(idx + 1) { | ||
123 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | ||
124 | continue; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | let start = last_batch_start; | ||
129 | last_batch_start = idx + 1; | ||
130 | |||
131 | let key = fst_path(&importables[start].1.path); | ||
132 | |||
133 | builder.insert(key, start as u64).unwrap(); | ||
134 | } | ||
135 | |||
136 | let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | ||
137 | let importables = importables.iter().map(|(item, _)| **item).collect(); | ||
138 | |||
139 | Arc::new(Self { map: import_map, fst, importables }) | ||
140 | } | ||
141 | |||
142 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. | ||
143 | pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { | ||
144 | Some(&self.map.get(&item)?.path) | ||
145 | } | ||
146 | |||
147 | pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { | ||
148 | self.map.get(&item) | ||
149 | } | ||
150 | } | ||
151 | |||
152 | impl PartialEq for ImportMap { | ||
153 | fn eq(&self, other: &Self) -> bool { | ||
154 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | ||
155 | self.map == other.map | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl Eq for ImportMap {} | ||
160 | |||
161 | impl fmt::Debug for ImportMap { | ||
162 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
163 | let mut importable_paths: Vec<_> = self | ||
164 | .map | ||
165 | .iter() | ||
166 | .map(|(item, info)| { | ||
167 | let ns = match item { | ||
168 | ItemInNs::Types(_) => "t", | ||
169 | ItemInNs::Values(_) => "v", | ||
170 | ItemInNs::Macros(_) => "m", | ||
171 | }; | ||
172 | format!("- {} ({})", info.path, ns) | ||
173 | }) | ||
174 | .collect(); | ||
175 | |||
176 | importable_paths.sort(); | ||
177 | f.write_str(&importable_paths.join("\n")) | ||
178 | } | ||
179 | } | ||
180 | |||
181 | fn fst_path(path: &ModPath) -> String { | ||
182 | let mut s = path.to_string(); | ||
183 | s.make_ascii_lowercase(); | ||
184 | s | ||
185 | } | ||
186 | |||
187 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | ||
188 | let lhs_str = fst_path(&lhs.path); | ||
189 | let rhs_str = fst_path(&rhs.path); | ||
190 | lhs_str.cmp(&rhs_str) | ||
191 | } | ||
192 | |||
193 | #[derive(Debug)] | ||
194 | pub struct Query { | ||
195 | query: String, | ||
196 | lowercased: String, | ||
197 | anchor_end: bool, | ||
198 | case_sensitive: bool, | ||
199 | limit: usize, | ||
200 | } | ||
201 | |||
202 | impl Query { | ||
203 | pub fn new(query: &str) -> Self { | ||
204 | Self { | ||
205 | lowercased: query.to_lowercase(), | ||
206 | query: query.to_string(), | ||
207 | anchor_end: false, | ||
208 | case_sensitive: false, | ||
209 | limit: usize::max_value(), | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | ||
214 | /// segment. | ||
215 | pub fn anchor_end(self) -> Self { | ||
216 | Self { anchor_end: true, ..self } | ||
217 | } | ||
218 | |||
219 | /// Limits the returned number of items to `limit`. | ||
220 | pub fn limit(self, limit: usize) -> Self { | ||
221 | Self { limit, ..self } | ||
222 | } | ||
223 | |||
224 | /// Respect casing of the query string when matching. | ||
225 | pub fn case_sensitive(self) -> Self { | ||
226 | Self { case_sensitive: true, ..self } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /// Searches dependencies of `krate` for an importable path matching `query`. | ||
231 | /// | ||
232 | /// This returns a list of items that could be imported from dependencies of `krate`. | ||
233 | pub fn search_dependencies<'a>( | ||
234 | db: &'a dyn DefDatabase, | ||
235 | krate: CrateId, | ||
236 | query: Query, | ||
237 | ) -> Vec<ItemInNs> { | ||
238 | let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); | ||
239 | |||
240 | let graph = db.crate_graph(); | ||
241 | let import_maps: Vec<_> = | ||
242 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); | ||
243 | |||
244 | let automaton = fst::automaton::Subsequence::new(&query.lowercased); | ||
245 | |||
246 | let mut op = fst::map::OpBuilder::new(); | ||
247 | for map in &import_maps { | ||
248 | op = op.add(map.fst.search(&automaton)); | ||
249 | } | ||
250 | |||
251 | let mut stream = op.union(); | ||
252 | let mut res = Vec::new(); | ||
253 | while let Some((_, indexed_values)) = stream.next() { | ||
254 | for indexed_value in indexed_values { | ||
255 | let import_map = &import_maps[indexed_value.index]; | ||
256 | let importables = &import_map.importables[indexed_value.value as usize..]; | ||
257 | |||
258 | // Path shared by the importable items in this group. | ||
259 | let path = &import_map.map[&importables[0]].path; | ||
260 | |||
261 | if query.anchor_end { | ||
262 | // Last segment must match query. | ||
263 | let last = path.segments.last().unwrap().to_string(); | ||
264 | if last.to_lowercase() != query.lowercased { | ||
265 | continue; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | // Add the items from this `ModPath` group. Those are all subsequent items in | ||
270 | // `importables` whose paths match `path`. | ||
271 | let iter = importables.iter().copied().take_while(|item| { | ||
272 | let item_path = &import_map.map[item].path; | ||
273 | fst_path(item_path) == fst_path(path) | ||
274 | }); | ||
275 | |||
276 | if query.case_sensitive { | ||
277 | // FIXME: This does not do a subsequence match. | ||
278 | res.extend(iter.filter(|item| { | ||
279 | let item_path = &import_map.map[item].path; | ||
280 | item_path.to_string().contains(&query.query) | ||
281 | })); | ||
282 | } else { | ||
283 | res.extend(iter); | ||
284 | } | ||
285 | |||
286 | if res.len() >= query.limit { | ||
287 | res.truncate(query.limit); | ||
288 | return res; | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | res | ||
294 | } | ||
295 | |||
296 | #[cfg(test)] | ||
297 | mod tests { | ||
298 | use super::*; | ||
299 | use crate::test_db::TestDB; | ||
300 | use insta::assert_snapshot; | ||
301 | use itertools::Itertools; | ||
302 | use ra_db::fixture::WithFixture; | ||
303 | use ra_db::{SourceDatabase, Upcast}; | ||
304 | |||
305 | fn import_map(ra_fixture: &str) -> String { | ||
306 | let db = TestDB::with_files(ra_fixture); | ||
307 | let crate_graph = db.crate_graph(); | ||
308 | |||
309 | let s = crate_graph | ||
310 | .iter() | ||
311 | .filter_map(|krate| { | ||
312 | let cdata = &crate_graph[krate]; | ||
313 | let name = cdata.display_name.as_ref()?; | ||
314 | |||
315 | let map = db.import_map(krate); | ||
316 | |||
317 | Some(format!("{}:\n{:?}", name, map)) | ||
318 | }) | ||
319 | .join("\n"); | ||
320 | s | ||
321 | } | ||
322 | |||
323 | fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { | ||
324 | let db = TestDB::with_files(ra_fixture); | ||
325 | let crate_graph = db.crate_graph(); | ||
326 | let krate = crate_graph | ||
327 | .iter() | ||
328 | .find(|krate| { | ||
329 | crate_graph[*krate].display_name.as_ref().map(|n| n.to_string()) | ||
330 | == Some(krate_name.to_string()) | ||
331 | }) | ||
332 | .unwrap(); | ||
333 | |||
334 | search_dependencies(db.upcast(), krate, query) | ||
335 | .into_iter() | ||
336 | .filter_map(|item| { | ||
337 | let mark = match item { | ||
338 | ItemInNs::Types(_) => "t", | ||
339 | ItemInNs::Values(_) => "v", | ||
340 | ItemInNs::Macros(_) => "m", | ||
341 | }; | ||
342 | item.krate(db.upcast()).map(|krate| { | ||
343 | let map = db.import_map(krate); | ||
344 | let path = map.path_of(item).unwrap(); | ||
345 | format!( | ||
346 | "{}::{} ({})", | ||
347 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
348 | path, | ||
349 | mark | ||
350 | ) | ||
351 | }) | ||
352 | }) | ||
353 | .join("\n") | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn smoke() { | ||
358 | let map = import_map( | ||
359 | r" | ||
360 | //- /main.rs crate:main deps:lib | ||
361 | |||
362 | mod private { | ||
363 | pub use lib::Pub; | ||
364 | pub struct InPrivateModule; | ||
365 | } | ||
366 | |||
367 | pub mod publ1 { | ||
368 | use lib::Pub; | ||
369 | } | ||
370 | |||
371 | pub mod real_pub { | ||
372 | pub use lib::Pub; | ||
373 | } | ||
374 | pub mod real_pu2 { // same path length as above | ||
375 | pub use lib::Pub; | ||
376 | } | ||
377 | |||
378 | //- /lib.rs crate:lib | ||
379 | pub struct Pub {} | ||
380 | pub struct Pub2; // t + v | ||
381 | struct Priv; | ||
382 | ", | ||
383 | ); | ||
384 | |||
385 | assert_snapshot!(map, @r###" | ||
386 | main: | ||
387 | - publ1 (t) | ||
388 | - real_pu2 (t) | ||
389 | - real_pub (t) | ||
390 | - real_pub::Pub (t) | ||
391 | lib: | ||
392 | - Pub (t) | ||
393 | - Pub2 (t) | ||
394 | - Pub2 (v) | ||
395 | "###); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn prefers_shortest_path() { | ||
400 | let map = import_map( | ||
401 | r" | ||
402 | //- /main.rs crate:main | ||
403 | |||
404 | pub mod sub { | ||
405 | pub mod subsub { | ||
406 | pub struct Def {} | ||
407 | } | ||
408 | |||
409 | pub use super::sub::subsub::Def; | ||
410 | } | ||
411 | ", | ||
412 | ); | ||
413 | |||
414 | assert_snapshot!(map, @r###" | ||
415 | main: | ||
416 | - sub (t) | ||
417 | - sub::Def (t) | ||
418 | - sub::subsub (t) | ||
419 | "###); | ||
420 | } | ||
421 | |||
422 | #[test] | ||
423 | fn type_reexport_cross_crate() { | ||
424 | // Reexports need to be visible from a crate, even if the original crate exports the item | ||
425 | // at a shorter path. | ||
426 | let map = import_map( | ||
427 | r" | ||
428 | //- /main.rs crate:main deps:lib | ||
429 | pub mod m { | ||
430 | pub use lib::S; | ||
431 | } | ||
432 | //- /lib.rs crate:lib | ||
433 | pub struct S; | ||
434 | ", | ||
435 | ); | ||
436 | |||
437 | assert_snapshot!(map, @r###" | ||
438 | main: | ||
439 | - m (t) | ||
440 | - m::S (t) | ||
441 | - m::S (v) | ||
442 | lib: | ||
443 | - S (t) | ||
444 | - S (v) | ||
445 | "###); | ||
446 | } | ||
447 | |||
448 | #[test] | ||
449 | fn macro_reexport() { | ||
450 | let map = import_map( | ||
451 | r" | ||
452 | //- /main.rs crate:main deps:lib | ||
453 | pub mod m { | ||
454 | pub use lib::pub_macro; | ||
455 | } | ||
456 | //- /lib.rs crate:lib | ||
457 | #[macro_export] | ||
458 | macro_rules! pub_macro { | ||
459 | () => {}; | ||
460 | } | ||
461 | ", | ||
462 | ); | ||
463 | |||
464 | assert_snapshot!(map, @r###" | ||
465 | main: | ||
466 | - m (t) | ||
467 | - m::pub_macro (m) | ||
468 | lib: | ||
469 | - pub_macro (m) | ||
470 | "###); | ||
471 | } | ||
472 | |||
473 | #[test] | ||
474 | fn module_reexport() { | ||
475 | // Reexporting modules from a dependency adds all contents to the import map. | ||
476 | let map = import_map( | ||
477 | r" | ||
478 | //- /main.rs crate:main deps:lib | ||
479 | pub use lib::module as reexported_module; | ||
480 | //- /lib.rs crate:lib | ||
481 | pub mod module { | ||
482 | pub struct S; | ||
483 | } | ||
484 | ", | ||
485 | ); | ||
486 | |||
487 | assert_snapshot!(map, @r###" | ||
488 | main: | ||
489 | - reexported_module (t) | ||
490 | - reexported_module::S (t) | ||
491 | - reexported_module::S (v) | ||
492 | lib: | ||
493 | - module (t) | ||
494 | - module::S (t) | ||
495 | - module::S (v) | ||
496 | "###); | ||
497 | } | ||
498 | |||
499 | #[test] | ||
500 | fn cyclic_module_reexport() { | ||
501 | // A cyclic reexport does not hang. | ||
502 | let map = import_map( | ||
503 | r" | ||
504 | //- /lib.rs crate:lib | ||
505 | pub mod module { | ||
506 | pub struct S; | ||
507 | pub use super::sub::*; | ||
508 | } | ||
509 | |||
510 | pub mod sub { | ||
511 | pub use super::module; | ||
512 | } | ||
513 | ", | ||
514 | ); | ||
515 | |||
516 | assert_snapshot!(map, @r###" | ||
517 | lib: | ||
518 | - module (t) | ||
519 | - module::S (t) | ||
520 | - module::S (v) | ||
521 | - sub (t) | ||
522 | "###); | ||
523 | } | ||
524 | |||
525 | #[test] | ||
526 | fn private_macro() { | ||
527 | let map = import_map( | ||
528 | r" | ||
529 | //- /lib.rs crate:lib | ||
530 | macro_rules! private_macro { | ||
531 | () => {}; | ||
532 | } | ||
533 | ", | ||
534 | ); | ||
535 | |||
536 | assert_snapshot!(map, @r###" | ||
537 | lib: | ||
538 | "###); | ||
539 | } | ||
540 | |||
541 | #[test] | ||
542 | fn namespacing() { | ||
543 | let map = import_map( | ||
544 | r" | ||
545 | //- /lib.rs crate:lib | ||
546 | pub struct Thing; // t + v | ||
547 | #[macro_export] | ||
548 | macro_rules! Thing { // m | ||
549 | () => {}; | ||
550 | } | ||
551 | ", | ||
552 | ); | ||
553 | |||
554 | assert_snapshot!(map, @r###" | ||
555 | lib: | ||
556 | - Thing (m) | ||
557 | - Thing (t) | ||
558 | - Thing (v) | ||
559 | "###); | ||
560 | |||
561 | let map = import_map( | ||
562 | r" | ||
563 | //- /lib.rs crate:lib | ||
564 | pub mod Thing {} // t | ||
565 | #[macro_export] | ||
566 | macro_rules! Thing { // m | ||
567 | () => {}; | ||
568 | } | ||
569 | ", | ||
570 | ); | ||
571 | |||
572 | assert_snapshot!(map, @r###" | ||
573 | lib: | ||
574 | - Thing (m) | ||
575 | - Thing (t) | ||
576 | "###); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn search() { | ||
581 | let ra_fixture = r#" | ||
582 | //- /main.rs crate:main deps:dep | ||
583 | //- /dep.rs crate:dep deps:tdep | ||
584 | use tdep::fmt as fmt_dep; | ||
585 | pub mod fmt { | ||
586 | pub trait Display { | ||
587 | fn fmt(); | ||
588 | } | ||
589 | } | ||
590 | #[macro_export] | ||
591 | macro_rules! Fmt { | ||
592 | () => {}; | ||
593 | } | ||
594 | pub struct Fmt; | ||
595 | |||
596 | pub fn format() {} | ||
597 | pub fn no() {} | ||
598 | |||
599 | //- /tdep.rs crate:tdep | ||
600 | pub mod fmt { | ||
601 | pub struct NotImportableFromMain; | ||
602 | } | ||
603 | "#; | ||
604 | |||
605 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); | ||
606 | assert_snapshot!(res, @r###" | ||
607 | dep::fmt (t) | ||
608 | dep::Fmt (t) | ||
609 | dep::Fmt (v) | ||
610 | dep::Fmt (m) | ||
611 | dep::fmt::Display (t) | ||
612 | dep::format (v) | ||
613 | "###); | ||
614 | |||
615 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); | ||
616 | assert_snapshot!(res, @r###" | ||
617 | dep::fmt (t) | ||
618 | dep::Fmt (t) | ||
619 | dep::Fmt (v) | ||
620 | dep::Fmt (m) | ||
621 | "###); | ||
622 | } | ||
623 | |||
624 | #[test] | ||
625 | fn search_casing() { | ||
626 | let ra_fixture = r#" | ||
627 | //- /main.rs crate:main deps:dep | ||
628 | //- /dep.rs crate:dep | ||
629 | |||
630 | pub struct fmt; | ||
631 | pub struct FMT; | ||
632 | "#; | ||
633 | |||
634 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); | ||
635 | |||
636 | assert_snapshot!(res, @r###" | ||
637 | dep::fmt (t) | ||
638 | dep::fmt (v) | ||
639 | dep::FMT (t) | ||
640 | dep::FMT (v) | ||
641 | "###); | ||
642 | |||
643 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); | ||
644 | |||
645 | assert_snapshot!(res, @r###" | ||
646 | dep::FMT (t) | ||
647 | dep::FMT (v) | ||
648 | "###); | ||
649 | } | ||
650 | |||
651 | #[test] | ||
652 | fn search_limit() { | ||
653 | let res = search_dependencies_of( | ||
654 | r#" | ||
655 | //- /main.rs crate:main deps:dep | ||
656 | //- /dep.rs crate:dep | ||
657 | pub mod fmt { | ||
658 | pub trait Display { | ||
659 | fn fmt(); | ||
660 | } | ||
661 | } | ||
662 | #[macro_export] | ||
663 | macro_rules! Fmt { | ||
664 | () => {}; | ||
665 | } | ||
666 | pub struct Fmt; | ||
667 | |||
668 | pub fn format() {} | ||
669 | pub fn no() {} | ||
670 | "#, | ||
671 | "main", | ||
672 | Query::new("").limit(2), | ||
673 | ); | ||
674 | assert_snapshot!(res, @r###" | ||
675 | dep::fmt (t) | ||
676 | dep::Fmt (t) | ||
677 | "###); | ||
678 | } | ||
679 | } | ||
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index fc15948ad..b03ba939a 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -3,11 +3,12 @@ | |||
3 | 3 | ||
4 | use hir_expand::name::Name; | 4 | use hir_expand::name::Name; |
5 | use once_cell::sync::Lazy; | 5 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | ||
6 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
7 | 8 | ||
8 | use crate::{ | 9 | use crate::{ |
9 | per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, | 10 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
10 | TraitId, | 11 | Lookup, MacroDefId, ModuleDefId, TraitId, |
11 | }; | 12 | }; |
12 | 13 | ||
13 | #[derive(Debug, Default, PartialEq, Eq)] | 14 | #[derive(Debug, Default, PartialEq, Eq)] |
@@ -203,4 +204,22 @@ impl ItemInNs { | |||
203 | ItemInNs::Macros(_) => None, | 204 | ItemInNs::Macros(_) => None, |
204 | } | 205 | } |
205 | } | 206 | } |
207 | |||
208 | /// Returns the crate defining this item (or `None` if `self` is built-in). | ||
209 | pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> { | ||
210 | Some(match self { | ||
211 | ItemInNs::Types(did) | ItemInNs::Values(did) => match did { | ||
212 | ModuleDefId::ModuleId(id) => id.krate, | ||
213 | ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate, | ||
214 | ModuleDefId::AdtId(id) => id.module(db).krate, | ||
215 | ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate, | ||
216 | ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate, | ||
217 | ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate, | ||
218 | ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate, | ||
219 | ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate, | ||
220 | ModuleDefId::BuiltinType(_) => return None, | ||
221 | }, | ||
222 | ItemInNs::Macros(id) => return id.krate, | ||
223 | }) | ||
224 | } | ||
206 | } | 225 | } |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 5325a2760..edc59e5a8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -43,6 +43,7 @@ pub mod child_by_source; | |||
43 | 43 | ||
44 | pub mod visibility; | 44 | pub mod visibility; |
45 | pub mod find_path; | 45 | pub mod find_path; |
46 | pub mod import_map; | ||
46 | 47 | ||
47 | #[cfg(test)] | 48 | #[cfg(test)] |
48 | mod test_db; | 49 | mod test_db; |
@@ -416,6 +417,7 @@ pub trait AsMacroCall { | |||
416 | fn as_call_id( | 417 | fn as_call_id( |
417 | &self, | 418 | &self, |
418 | db: &dyn db::DefDatabase, | 419 | db: &dyn db::DefDatabase, |
420 | krate: CrateId, | ||
419 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 421 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
420 | ) -> Option<MacroCallId>; | 422 | ) -> Option<MacroCallId>; |
421 | } | 423 | } |
@@ -424,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
424 | fn as_call_id( | 426 | fn as_call_id( |
425 | &self, | 427 | &self, |
426 | db: &dyn db::DefDatabase, | 428 | db: &dyn db::DefDatabase, |
429 | krate: CrateId, | ||
427 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 430 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
428 | ) -> Option<MacroCallId> { | 431 | ) -> Option<MacroCallId> { |
429 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 432 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
430 | let h = Hygiene::new(db.upcast(), self.file_id); | 433 | let h = Hygiene::new(db.upcast(), self.file_id); |
431 | let path = path::ModPath::from_src(self.value.path()?, &h)?; | 434 | let path = path::ModPath::from_src(self.value.path()?, &h)?; |
432 | 435 | ||
433 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver) | 436 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) |
434 | } | 437 | } |
435 | } | 438 | } |
436 | 439 | ||
@@ -451,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
451 | fn as_call_id( | 454 | fn as_call_id( |
452 | &self, | 455 | &self, |
453 | db: &dyn db::DefDatabase, | 456 | db: &dyn db::DefDatabase, |
457 | krate: CrateId, | ||
454 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 458 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
455 | ) -> Option<MacroCallId> { | 459 | ) -> Option<MacroCallId> { |
456 | let def: MacroDefId = resolver(self.path.clone())?; | 460 | let def: MacroDefId = resolver(self.path.clone())?; |
@@ -460,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
460 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); | 464 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); |
461 | 465 | ||
462 | Some( | 466 | Some( |
463 | expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| { | 467 | expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { |
464 | resolver(path::ModPath::from_src(path, &hygiene)?) | 468 | resolver(path::ModPath::from_src(path, &hygiene)?) |
465 | })? | 469 | })? |
466 | .into(), | 470 | .into(), |
467 | ) | 471 | ) |
468 | } else { | 472 | } else { |
469 | Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into()) | 473 | Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into()) |
470 | } | 474 | } |
471 | } | 475 | } |
472 | } | 476 | } |
@@ -475,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { | |||
475 | fn as_call_id( | 479 | fn as_call_id( |
476 | &self, | 480 | &self, |
477 | db: &dyn db::DefDatabase, | 481 | db: &dyn db::DefDatabase, |
482 | krate: CrateId, | ||
478 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 483 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
479 | ) -> Option<MacroCallId> { | 484 | ) -> Option<MacroCallId> { |
480 | let def = resolver(self.path.clone())?; | 485 | let def = resolver(self.path.clone())?; |
481 | Some( | 486 | Some( |
482 | def.as_lazy_macro( | 487 | def.as_lazy_macro( |
483 | db.upcast(), | 488 | db.upcast(), |
489 | krate, | ||
484 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), | 490 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), |
485 | ) | 491 | ) |
486 | .into(), | 492 | .into(), |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 353a31ad4..976e5e585 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -571,16 +571,18 @@ impl DefCollector<'_> { | |||
571 | return false; | 571 | return false; |
572 | } | 572 | } |
573 | 573 | ||
574 | if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { | 574 | if let Some(call_id) = |
575 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 575 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
576 | self.db, | 576 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
577 | ResolveMode::Other, | 577 | self.db, |
578 | directive.module_id, | 578 | ResolveMode::Other, |
579 | &path, | 579 | directive.module_id, |
580 | BuiltinShadowMode::Module, | 580 | &path, |
581 | ); | 581 | BuiltinShadowMode::Module, |
582 | resolved_res.resolved_def.take_macros() | 582 | ); |
583 | }) { | 583 | resolved_res.resolved_def.take_macros() |
584 | }) | ||
585 | { | ||
584 | resolved.push((directive.module_id, call_id, directive.depth)); | 586 | resolved.push((directive.module_id, call_id, directive.depth)); |
585 | res = ReachedFixedPoint::No; | 587 | res = ReachedFixedPoint::No; |
586 | return false; | 588 | return false; |
@@ -589,9 +591,10 @@ impl DefCollector<'_> { | |||
589 | true | 591 | true |
590 | }); | 592 | }); |
591 | attribute_macros.retain(|directive| { | 593 | attribute_macros.retain(|directive| { |
592 | if let Some(call_id) = directive | 594 | if let Some(call_id) = |
593 | .ast_id | 595 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
594 | .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) | 596 | self.resolve_attribute_macro(&directive, &path) |
597 | }) | ||
595 | { | 598 | { |
596 | resolved.push((directive.module_id, call_id, 0)); | 599 | resolved.push((directive.module_id, call_id, 0)); |
597 | res = ReachedFixedPoint::No; | 600 | res = ReachedFixedPoint::No; |
@@ -957,11 +960,13 @@ impl ModCollector<'_, '_> { | |||
957 | } | 960 | } |
958 | 961 | ||
959 | // Case 2: try to resolve in legacy scope and expand macro_rules | 962 | // Case 2: try to resolve in legacy scope and expand macro_rules |
960 | if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { | 963 | if let Some(macro_call_id) = |
961 | path.as_ident().and_then(|name| { | 964 | ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { |
962 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 965 | path.as_ident().and_then(|name| { |
966 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | ||
967 | }) | ||
963 | }) | 968 | }) |
964 | }) { | 969 | { |
965 | self.def_collector.unexpanded_macros.push(MacroDirective { | 970 | self.def_collector.unexpanded_macros.push(MacroDirective { |
966 | module_id: self.module_id, | 971 | module_id: self.module_id, |
967 | ast_id, | 972 | ast_id, |
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index 386c5cade..cede4a6fc 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs | |||
@@ -61,7 +61,7 @@ impl ModDir { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | for candidate in candidate_files.iter() { | 63 | for candidate in candidate_files.iter() { |
64 | if let Some(file_id) = db.resolve_relative_path(file_id, candidate) { | 64 | if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) { |
65 | let mut root_non_dir_owner = false; | 65 | let mut root_non_dir_owner = false; |
66 | let mut mod_path = RelativePathBuf::new(); | 66 | let mut mod_path = RelativePathBuf::new(); |
67 | if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { | 67 | if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index e84efe2ab..ba16442bd 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -76,6 +76,19 @@ impl ModPath { | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | /// Returns the number of segments in the path (counting special segments like `$crate` and | ||
80 | /// `super`). | ||
81 | pub fn len(&self) -> usize { | ||
82 | self.segments.len() | ||
83 | + match self.kind { | ||
84 | PathKind::Plain => 0, | ||
85 | PathKind::Super(i) => i as usize, | ||
86 | PathKind::Crate => 1, | ||
87 | PathKind::Abs => 0, | ||
88 | PathKind::DollarCrate(_) => 1, | ||
89 | } | ||
90 | } | ||
91 | |||
79 | pub fn is_ident(&self) -> bool { | 92 | pub fn is_ident(&self) -> bool { |
80 | self.kind == PathKind::Plain && self.segments.len() == 1 | 93 | self.kind == PathKind::Plain && self.segments.len() == 1 |
81 | } | 94 | } |
@@ -273,7 +286,7 @@ impl From<Name> for ModPath { | |||
273 | impl Display for ModPath { | 286 | impl Display for ModPath { |
274 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 287 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
275 | let mut first_segment = true; | 288 | let mut first_segment = true; |
276 | let mut add_segment = |s| { | 289 | let mut add_segment = |s| -> fmt::Result { |
277 | if !first_segment { | 290 | if !first_segment { |
278 | f.write_str("::")?; | 291 | f.write_str("::")?; |
279 | } | 292 | } |
@@ -310,16 +323,16 @@ pub use hir_expand::name as __name; | |||
310 | 323 | ||
311 | #[macro_export] | 324 | #[macro_export] |
312 | macro_rules! __known_path { | 325 | macro_rules! __known_path { |
313 | (std::iter::IntoIterator) => {}; | 326 | (core::iter::IntoIterator) => {}; |
314 | (std::result::Result) => {}; | 327 | (core::result::Result) => {}; |
315 | (std::ops::Range) => {}; | 328 | (core::ops::Range) => {}; |
316 | (std::ops::RangeFrom) => {}; | 329 | (core::ops::RangeFrom) => {}; |
317 | (std::ops::RangeFull) => {}; | 330 | (core::ops::RangeFull) => {}; |
318 | (std::ops::RangeTo) => {}; | 331 | (core::ops::RangeTo) => {}; |
319 | (std::ops::RangeToInclusive) => {}; | 332 | (core::ops::RangeToInclusive) => {}; |
320 | (std::ops::RangeInclusive) => {}; | 333 | (core::ops::RangeInclusive) => {}; |
321 | (std::future::Future) => {}; | 334 | (core::future::Future) => {}; |
322 | (std::ops::Try) => {}; | 335 | (core::ops::Try) => {}; |
323 | ($path:path) => { | 336 | ($path:path) => { |
324 | compile_error!("Please register your known path in the path module") | 337 | compile_error!("Please register your known path in the path module") |
325 | }; | 338 | }; |
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs index 6e435c8c1..74665c588 100644 --- a/crates/ra_hir_def/src/per_ns.rs +++ b/crates/ra_hir_def/src/per_ns.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | use hir_expand::MacroDefId; | 6 | use hir_expand::MacroDefId; |
7 | 7 | ||
8 | use crate::{visibility::Visibility, ModuleDefId}; | 8 | use crate::{item_scope::ItemInNs, visibility::Visibility, ModuleDefId}; |
9 | 9 | ||
10 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
11 | pub struct PerNs { | 11 | pub struct PerNs { |
@@ -84,4 +84,12 @@ impl PerNs { | |||
84 | macros: self.macros.or(other.macros), | 84 | macros: self.macros.or(other.macros), |
85 | } | 85 | } |
86 | } | 86 | } |
87 | |||
88 | pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> { | ||
89 | self.types | ||
90 | .map(|it| ItemInNs::Types(it.0)) | ||
91 | .into_iter() | ||
92 | .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter()) | ||
93 | .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter()) | ||
94 | } | ||
87 | } | 95 | } |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index eb83dee79..4581d8745 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -6,9 +6,8 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use hir_expand::db::AstDatabase; | 8 | use hir_expand::db::AstDatabase; |
9 | use ra_db::{ | 9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; |
10 | salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath, Upcast, | 10 | use rustc_hash::FxHashSet; |
11 | }; | ||
12 | 11 | ||
13 | use crate::db::DefDatabase; | 12 | use crate::db::DefDatabase; |
14 | 13 | ||
@@ -58,24 +57,12 @@ impl FileLoader for TestDB { | |||
58 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 57 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
59 | FileLoaderDelegate(self).file_text(file_id) | 58 | FileLoaderDelegate(self).file_text(file_id) |
60 | } | 59 | } |
61 | fn resolve_relative_path( | 60 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
62 | &self, | 61 | FileLoaderDelegate(self).resolve_path(anchor, path) |
63 | anchor: FileId, | ||
64 | relative_path: &RelativePath, | ||
65 | ) -> Option<FileId> { | ||
66 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
67 | } | 62 | } |
68 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 63 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
69 | FileLoaderDelegate(self).relevant_crates(file_id) | 64 | FileLoaderDelegate(self).relevant_crates(file_id) |
70 | } | 65 | } |
71 | |||
72 | fn resolve_extern_path( | ||
73 | &self, | ||
74 | extern_id: ExternSourceId, | ||
75 | relative_path: &RelativePath, | ||
76 | ) -> Option<FileId> { | ||
77 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
78 | } | ||
79 | } | 66 | } |
80 | 67 | ||
81 | impl TestDB { | 68 | impl TestDB { |
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 2cd522766..e5c9f3e99 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml | |||
@@ -10,6 +10,7 @@ doctest = false | |||
10 | [dependencies] | 10 | [dependencies] |
11 | log = "0.4.8" | 11 | log = "0.4.8" |
12 | either = "1.5.3" | 12 | either = "1.5.3" |
13 | rustc-hash = "1.0.0" | ||
13 | 14 | ||
14 | ra_arena = { path = "../ra_arena" } | 15 | ra_arena = { path = "../ra_arena" } |
15 | ra_db = { path = "../ra_db" } | 16 | ra_db = { path = "../ra_db" } |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 1dc9cac66..26b667b55 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -8,8 +8,7 @@ use ra_syntax::{ | |||
8 | match_ast, | 8 | match_ast, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::db::AstDatabase; | 11 | use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; |
12 | use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( $($trait:ident => $expand:ident),* ) => { | 14 | ( $($trait:ident => $expand:ident),* ) => { |
@@ -156,23 +155,13 @@ fn expand_simple_derive( | |||
156 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | 155 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { |
157 | // FIXME: make hygiene works for builtin derive macro | 156 | // FIXME: make hygiene works for builtin derive macro |
158 | // such that $crate can be used here. | 157 | // such that $crate can be used here. |
159 | |||
160 | let m: MacroCallId = id.into(); | ||
161 | let file_id = m.as_file().original_file(db); | ||
162 | let cg = db.crate_graph(); | 158 | let cg = db.crate_graph(); |
163 | let krates = db.relevant_crates(file_id); | 159 | let krate = db.lookup_intern_macro(id).krate; |
164 | let krate = match krates.get(0) { | ||
165 | Some(krate) => krate, | ||
166 | None => { | ||
167 | let tt = quote! { core }; | ||
168 | return tt.token_trees[0].clone(); | ||
169 | } | ||
170 | }; | ||
171 | 160 | ||
172 | // XXX | 161 | // XXX |
173 | // All crates except core itself should have a dependency on core, | 162 | // All crates except core itself should have a dependency on core, |
174 | // We detect `core` by seeing whether it doesn't have such a dependency. | 163 | // We detect `core` by seeing whether it doesn't have such a dependency. |
175 | let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { | 164 | let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { |
176 | quote! { core } | 165 | quote! { core } |
177 | } else { | 166 | } else { |
178 | quote! { crate } | 167 | quote! { crate } |
@@ -264,10 +253,12 @@ fn partial_ord_expand( | |||
264 | 253 | ||
265 | #[cfg(test)] | 254 | #[cfg(test)] |
266 | mod tests { | 255 | mod tests { |
267 | use super::*; | ||
268 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
269 | use name::{known, Name}; | 256 | use name::{known, Name}; |
270 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 257 | use ra_db::{fixture::WithFixture, CrateId, SourceDatabase}; |
258 | |||
259 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
260 | |||
261 | use super::*; | ||
271 | 262 | ||
272 | fn expand_builtin_derive(s: &str, name: Name) -> String { | 263 | fn expand_builtin_derive(s: &str, name: Name) -> String { |
273 | let def = find_builtin_derive(&name).unwrap(); | 264 | let def = find_builtin_derive(&name).unwrap(); |
@@ -291,7 +282,11 @@ mod tests { | |||
291 | 282 | ||
292 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); | 283 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); |
293 | 284 | ||
294 | let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; | 285 | let loc = MacroCallLoc { |
286 | def, | ||
287 | krate: CrateId(0), | ||
288 | kind: MacroCallKind::Attr(attr_id, name.to_string()), | ||
289 | }; | ||
295 | 290 | ||
296 | let id: MacroCallId = db.intern_macro(loc).into(); | 291 | let id: MacroCallId = db.intern_macro(loc).into(); |
297 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 292 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 3bce8f673..b50eb347c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -1,15 +1,14 @@ | |||
1 | //! Builtin macro | 1 | //! Builtin macro |
2 | use crate::db::AstDatabase; | ||
3 | use crate::{ | 2 | use crate::{ |
4 | ast::{self, AstToken, HasStringValue}, | 3 | db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, |
5 | name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, | 4 | MacroDefId, MacroDefKind, TextSize, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; | ||
9 | use either::Either; | 7 | use either::Either; |
10 | use mbe::parse_to_token_tree; | 8 | use mbe::parse_to_token_tree; |
11 | use ra_db::{FileId, RelativePath}; | 9 | use ra_db::FileId; |
12 | use ra_parser::FragmentKind; | 10 | use ra_parser::FragmentKind; |
11 | use ra_syntax::ast::{self, AstToken, HasStringValue}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { | 14 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { |
@@ -295,19 +294,13 @@ fn concat_expand( | |||
295 | 294 | ||
296 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { | 295 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { |
297 | let call_site = call_id.as_file().original_file(db); | 296 | let call_site = call_id.as_file().original_file(db); |
298 | 297 | let res = db.resolve_path(call_site, path)?; | |
299 | // Handle trivial case | 298 | // Prevent include itself |
300 | if let Some(res) = db.resolve_relative_path(call_site, &RelativePath::new(&path)) { | 299 | if res == call_site { |
301 | // Prevent include itself | 300 | None |
302 | return if res == call_site { None } else { Some(res) }; | 301 | } else { |
302 | Some(res) | ||
303 | } | 303 | } |
304 | |||
305 | // Extern paths ? | ||
306 | let krate = *db.relevant_crates(call_site).get(0)?; | ||
307 | let (extern_source_id, relative_file) = | ||
308 | db.crate_graph()[krate].extern_source.extern_path(path)?; | ||
309 | |||
310 | db.resolve_extern_path(extern_source_id, &relative_file) | ||
311 | } | 304 | } |
312 | 305 | ||
313 | fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { | 306 | fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { |
@@ -339,10 +332,7 @@ fn include_expand( | |||
339 | } | 332 | } |
340 | 333 | ||
341 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 334 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { |
342 | let call_id: MacroCallId = arg_id.into(); | 335 | let krate = db.lookup_intern_eager_expansion(arg_id).krate; |
343 | let original_file = call_id.as_file().original_file(db); | ||
344 | |||
345 | let krate = *db.relevant_crates(original_file).get(0)?; | ||
346 | db.crate_graph()[krate].env.get(key) | 336 | db.crate_graph()[krate].env.get(key) |
347 | } | 337 | } |
348 | 338 | ||
@@ -401,6 +391,7 @@ mod tests { | |||
401 | 391 | ||
402 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 392 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); |
403 | 393 | ||
394 | let krate = CrateId(0); | ||
404 | let file_id = match expander { | 395 | let file_id = match expander { |
405 | Either::Left(expander) => { | 396 | Either::Left(expander) => { |
406 | // the first one should be a macro_rules | 397 | // the first one should be a macro_rules |
@@ -413,6 +404,7 @@ mod tests { | |||
413 | 404 | ||
414 | let loc = MacroCallLoc { | 405 | let loc = MacroCallLoc { |
415 | def, | 406 | def, |
407 | krate, | ||
416 | kind: MacroCallKind::FnLike(AstId::new( | 408 | kind: MacroCallKind::FnLike(AstId::new( |
417 | file_id.into(), | 409 | file_id.into(), |
418 | ast_id_map.ast_id(¯o_calls[1]), | 410 | ast_id_map.ast_id(¯o_calls[1]), |
@@ -425,7 +417,7 @@ mod tests { | |||
425 | Either::Right(expander) => { | 417 | Either::Right(expander) => { |
426 | // the first one should be a macro_rules | 418 | // the first one should be a macro_rules |
427 | let def = MacroDefId { | 419 | let def = MacroDefId { |
428 | krate: Some(CrateId(0)), | 420 | krate: Some(krate), |
429 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 421 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
430 | kind: MacroDefKind::BuiltInEager(expander), | 422 | kind: MacroDefKind::BuiltInEager(expander), |
431 | local_inner: false, | 423 | local_inner: false, |
@@ -439,6 +431,7 @@ mod tests { | |||
439 | def, | 431 | def, |
440 | fragment: FragmentKind::Expr, | 432 | fragment: FragmentKind::Expr, |
441 | subtree: Arc::new(parsed_args.clone()), | 433 | subtree: Arc::new(parsed_args.clone()), |
434 | krate, | ||
442 | file_id: file_id.into(), | 435 | file_id: file_id.into(), |
443 | } | 436 | } |
444 | }); | 437 | }); |
@@ -448,6 +441,7 @@ mod tests { | |||
448 | def, | 441 | def, |
449 | fragment, | 442 | fragment, |
450 | subtree: Arc::new(subtree), | 443 | subtree: Arc::new(subtree), |
444 | krate, | ||
451 | file_id: file_id.into(), | 445 | file_id: file_id.into(), |
452 | }; | 446 | }; |
453 | 447 | ||
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index 932f47c30..302d2b3e0 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs | |||
@@ -25,12 +25,14 @@ use crate::{ | |||
25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | use ra_db::CrateId; | ||
28 | use ra_parser::FragmentKind; | 29 | use ra_parser::FragmentKind; |
29 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; | 30 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; |
30 | use std::sync::Arc; | 31 | use std::sync::Arc; |
31 | 32 | ||
32 | pub fn expand_eager_macro( | 33 | pub fn expand_eager_macro( |
33 | db: &dyn AstDatabase, | 34 | db: &dyn AstDatabase, |
35 | krate: CrateId, | ||
34 | macro_call: InFile<ast::MacroCall>, | 36 | macro_call: InFile<ast::MacroCall>, |
35 | def: MacroDefId, | 37 | def: MacroDefId, |
36 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 38 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
@@ -47,6 +49,7 @@ pub fn expand_eager_macro( | |||
47 | def, | 49 | def, |
48 | fragment: FragmentKind::Expr, | 50 | fragment: FragmentKind::Expr, |
49 | subtree: Arc::new(parsed_args.clone()), | 51 | subtree: Arc::new(parsed_args.clone()), |
52 | krate, | ||
50 | file_id: macro_call.file_id, | 53 | file_id: macro_call.file_id, |
51 | } | 54 | } |
52 | }); | 55 | }); |
@@ -56,14 +59,20 @@ pub fn expand_eager_macro( | |||
56 | let result = eager_macro_recur( | 59 | let result = eager_macro_recur( |
57 | db, | 60 | db, |
58 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), | 61 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), |
62 | krate, | ||
59 | resolver, | 63 | resolver, |
60 | )?; | 64 | )?; |
61 | let subtree = to_subtree(&result)?; | 65 | let subtree = to_subtree(&result)?; |
62 | 66 | ||
63 | if let MacroDefKind::BuiltInEager(eager) = def.kind { | 67 | if let MacroDefKind::BuiltInEager(eager) = def.kind { |
64 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; | 68 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; |
65 | let eager = | 69 | let eager = EagerCallLoc { |
66 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; | 70 | def, |
71 | fragment, | ||
72 | subtree: Arc::new(subtree), | ||
73 | krate, | ||
74 | file_id: macro_call.file_id, | ||
75 | }; | ||
67 | 76 | ||
68 | Some(db.intern_eager_expansion(eager)) | 77 | Some(db.intern_eager_expansion(eager)) |
69 | } else { | 78 | } else { |
@@ -81,11 +90,12 @@ fn lazy_expand( | |||
81 | db: &dyn AstDatabase, | 90 | db: &dyn AstDatabase, |
82 | def: &MacroDefId, | 91 | def: &MacroDefId, |
83 | macro_call: InFile<ast::MacroCall>, | 92 | macro_call: InFile<ast::MacroCall>, |
93 | krate: CrateId, | ||
84 | ) -> Option<InFile<SyntaxNode>> { | 94 | ) -> Option<InFile<SyntaxNode>> { |
85 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 95 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
86 | 96 | ||
87 | let id: MacroCallId = | 97 | let id: MacroCallId = |
88 | def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); | 98 | def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); |
89 | 99 | ||
90 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) | 100 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) |
91 | } | 101 | } |
@@ -93,6 +103,7 @@ fn lazy_expand( | |||
93 | fn eager_macro_recur( | 103 | fn eager_macro_recur( |
94 | db: &dyn AstDatabase, | 104 | db: &dyn AstDatabase, |
95 | curr: InFile<SyntaxNode>, | 105 | curr: InFile<SyntaxNode>, |
106 | krate: CrateId, | ||
96 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 107 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
97 | ) -> Option<SyntaxNode> { | 108 | ) -> Option<SyntaxNode> { |
98 | let original = curr.value.clone(); | 109 | let original = curr.value.clone(); |
@@ -105,18 +116,23 @@ fn eager_macro_recur( | |||
105 | let def: MacroDefId = macro_resolver(child.path()?)?; | 116 | let def: MacroDefId = macro_resolver(child.path()?)?; |
106 | let insert = match def.kind { | 117 | let insert = match def.kind { |
107 | MacroDefKind::BuiltInEager(_) => { | 118 | MacroDefKind::BuiltInEager(_) => { |
108 | let id: MacroCallId = | 119 | let id: MacroCallId = expand_eager_macro( |
109 | expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? | 120 | db, |
110 | .into(); | 121 | krate, |
122 | curr.with_value(child.clone()), | ||
123 | def, | ||
124 | macro_resolver, | ||
125 | )? | ||
126 | .into(); | ||
111 | db.parse_or_expand(id.as_file())? | 127 | db.parse_or_expand(id.as_file())? |
112 | } | 128 | } |
113 | MacroDefKind::Declarative | 129 | MacroDefKind::Declarative |
114 | | MacroDefKind::BuiltIn(_) | 130 | | MacroDefKind::BuiltIn(_) |
115 | | MacroDefKind::BuiltInDerive(_) | 131 | | MacroDefKind::BuiltInDerive(_) |
116 | | MacroDefKind::CustomDerive(_) => { | 132 | | MacroDefKind::CustomDerive(_) => { |
117 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; | 133 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; |
118 | // replace macro inside | 134 | // replace macro inside |
119 | eager_macro_recur(db, expanded, macro_resolver)? | 135 | eager_macro_recur(db, expanded, krate, macro_resolver)? |
120 | } | 136 | } |
121 | }; | 137 | }; |
122 | 138 | ||
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index f440c073b..5eac2605b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -209,8 +209,13 @@ pub struct MacroDefId { | |||
209 | } | 209 | } |
210 | 210 | ||
211 | impl MacroDefId { | 211 | impl MacroDefId { |
212 | pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { | 212 | pub fn as_lazy_macro( |
213 | db.intern_macro(MacroCallLoc { def: self, kind }) | 213 | self, |
214 | db: &dyn db::AstDatabase, | ||
215 | krate: CrateId, | ||
216 | kind: MacroCallKind, | ||
217 | ) -> LazyMacroId { | ||
218 | db.intern_macro(MacroCallLoc { def: self, krate, kind }) | ||
214 | } | 219 | } |
215 | } | 220 | } |
216 | 221 | ||
@@ -227,6 +232,7 @@ pub enum MacroDefKind { | |||
227 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 232 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
228 | pub struct MacroCallLoc { | 233 | pub struct MacroCallLoc { |
229 | pub(crate) def: MacroDefId, | 234 | pub(crate) def: MacroDefId, |
235 | pub(crate) krate: CrateId, | ||
230 | pub(crate) kind: MacroCallKind, | 236 | pub(crate) kind: MacroCallKind, |
231 | } | 237 | } |
232 | 238 | ||
@@ -274,6 +280,7 @@ pub struct EagerCallLoc { | |||
274 | pub(crate) def: MacroDefId, | 280 | pub(crate) def: MacroDefId, |
275 | pub(crate) fragment: FragmentKind, | 281 | pub(crate) fragment: FragmentKind, |
276 | pub(crate) subtree: Arc<tt::Subtree>, | 282 | pub(crate) subtree: Arc<tt::Subtree>, |
283 | pub(crate) krate: CrateId, | ||
277 | pub(crate) file_id: HirFileId, | 284 | pub(crate) file_id: HirFileId, |
278 | } | 285 | } |
279 | 286 | ||
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index ea495cb11..660bdfe33 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -153,6 +153,7 @@ pub mod known { | |||
153 | str, | 153 | str, |
154 | // Special names | 154 | // Special names |
155 | macro_rules, | 155 | macro_rules, |
156 | doc, | ||
156 | // Components of known path (value or mod name) | 157 | // Components of known path (value or mod name) |
157 | std, | 158 | std, |
158 | core, | 159 | core, |
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index c1fb762de..09fc18c36 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs | |||
@@ -5,7 +5,8 @@ use std::{ | |||
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; |
9 | use rustc_hash::FxHashSet; | ||
9 | 10 | ||
10 | #[salsa::database( | 11 | #[salsa::database( |
11 | ra_db::SourceDatabaseExtStorage, | 12 | ra_db::SourceDatabaseExtStorage, |
@@ -41,21 +42,10 @@ impl FileLoader for TestDB { | |||
41 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 42 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
42 | FileLoaderDelegate(self).file_text(file_id) | 43 | FileLoaderDelegate(self).file_text(file_id) |
43 | } | 44 | } |
44 | fn resolve_relative_path( | 45 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
45 | &self, | 46 | FileLoaderDelegate(self).resolve_path(anchor, path) |
46 | anchor: FileId, | ||
47 | relative_path: &RelativePath, | ||
48 | ) -> Option<FileId> { | ||
49 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
50 | } | 47 | } |
51 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 48 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
52 | FileLoaderDelegate(self).relevant_crates(file_id) | 49 | FileLoaderDelegate(self).relevant_crates(file_id) |
53 | } | 50 | } |
54 | fn resolve_extern_path( | ||
55 | &self, | ||
56 | anchor: ExternSourceId, | ||
57 | relative_path: &RelativePath, | ||
58 | ) -> Option<FileId> { | ||
59 | FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path) | ||
60 | } | ||
61 | } | 51 | } |
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 4b8dcdc07..112fcd07e 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" } | |||
27 | 27 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } | 30 | chalk-solve = "0.11" |
31 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } | 31 | chalk-ir = "0.11" |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | insta = "0.16.0" | 34 | insta = "0.16.0" |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 0a8bb24ac..bf71d38d6 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -3,8 +3,8 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalFieldId, TraitId, TypeParamId, | 6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId, |
7 | VariantId, | 7 | TypeParamId, VariantId, |
8 | }; | 8 | }; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | 10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; |
@@ -13,8 +13,8 @@ use ra_prof::profile; | |||
13 | use crate::{ | 13 | use crate::{ |
14 | method_resolution::{CrateImplDefs, TyFingerprint}, | 14 | method_resolution::{CrateImplDefs, TyFingerprint}, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::{chalk, AssocTyValue, Impl}, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, | 16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, |
17 | TyDefId, TypeCtor, ValueTyDefId, | 17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, |
18 | }; | 18 | }; |
19 | use hir_expand::name::Name; | 19 | use hir_expand::name::Name; |
20 | 20 | ||
@@ -48,6 +48,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
48 | #[salsa::invoke(crate::callable_item_sig)] | 48 | #[salsa::invoke(crate::callable_item_sig)] |
49 | fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; | 49 | fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; |
50 | 50 | ||
51 | #[salsa::invoke(crate::lower::return_type_impl_traits)] | ||
52 | fn return_type_impl_traits( | ||
53 | &self, | ||
54 | def: FunctionId, | ||
55 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>; | ||
56 | |||
51 | #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] | 57 | #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] |
52 | #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] | 58 | #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] |
53 | fn generic_predicates_for_param( | 59 | fn generic_predicates_for_param( |
@@ -80,6 +86,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
80 | #[salsa::interned] | 86 | #[salsa::interned] |
81 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | 87 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; |
82 | #[salsa::interned] | 88 | #[salsa::interned] |
89 | fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; | ||
90 | #[salsa::interned] | ||
83 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; | 91 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; |
84 | #[salsa::interned] | 92 | #[salsa::interned] |
85 | fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; | 93 | fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; |
@@ -142,3 +150,7 @@ fn hir_database_is_object_safe() { | |||
142 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 150 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
143 | pub struct GlobalTypeParamId(salsa::InternId); | 151 | pub struct GlobalTypeParamId(salsa::InternId); |
144 | impl_intern_key!(GlobalTypeParamId); | 152 | impl_intern_key!(GlobalTypeParamId); |
153 | |||
154 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
155 | pub struct InternedOpaqueTyId(salsa::InternId); | ||
156 | impl_intern_key!(InternedOpaqueTyId); | ||
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index b9c4d2e89..3c97e1354 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs | |||
@@ -4,7 +4,7 @@ use std::fmt; | |||
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, | 6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, |
7 | Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 7 | Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
8 | }; | 8 | }; |
9 | use hir_def::{ | 9 | use hir_def::{ |
10 | find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, | 10 | find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, |
@@ -359,6 +359,21 @@ impl HirDisplay for ApplicationTy { | |||
359 | write!(f, ">")?; | 359 | write!(f, ">")?; |
360 | } | 360 | } |
361 | } | 361 | } |
362 | TypeCtor::OpaqueType(opaque_ty_id) => { | ||
363 | let bounds = match opaque_ty_id { | ||
364 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
365 | let datas = | ||
366 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
367 | let data = (*datas) | ||
368 | .as_ref() | ||
369 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
370 | data.clone().subst(&self.parameters) | ||
371 | } | ||
372 | }; | ||
373 | write!(f, "impl ")?; | ||
374 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
375 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | ||
376 | } | ||
362 | TypeCtor::Closure { .. } => { | 377 | TypeCtor::Closure { .. } => { |
363 | let sig = self.parameters[0].callable_sig(f.db); | 378 | let sig = self.parameters[0].callable_sig(f.db); |
364 | if let Some(sig) = sig { | 379 | if let Some(sig) = sig { |
@@ -427,14 +442,24 @@ impl HirDisplay for Ty { | |||
427 | } | 442 | } |
428 | } | 443 | } |
429 | Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, | 444 | Ty::Bound(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, |
430 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | 445 | Ty::Dyn(predicates) => { |
431 | match self { | 446 | write!(f, "dyn ")?; |
432 | Ty::Dyn(_) => write!(f, "dyn ")?, | ||
433 | Ty::Opaque(_) => write!(f, "impl ")?, | ||
434 | _ => unreachable!(), | ||
435 | }; | ||
436 | write_bounds_like_dyn_trait(predicates, f)?; | 447 | write_bounds_like_dyn_trait(predicates, f)?; |
437 | } | 448 | } |
449 | Ty::Opaque(opaque_ty) => { | ||
450 | let bounds = match opaque_ty.opaque_ty_id { | ||
451 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
452 | let datas = | ||
453 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
454 | let data = (*datas) | ||
455 | .as_ref() | ||
456 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
457 | data.clone().subst(&opaque_ty.parameters) | ||
458 | } | ||
459 | }; | ||
460 | write!(f, "impl ")?; | ||
461 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
462 | } | ||
438 | Ty::Unknown => write!(f, "{{unknown}}")?, | 463 | Ty::Unknown => write!(f, "{{unknown}}")?, |
439 | Ty::Infer(..) => write!(f, "_")?, | 464 | Ty::Infer(..) => write!(f, "_")?, |
440 | } | 465 | } |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index f04968e14..7db928dde 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -226,17 +226,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
226 | None => return, | 226 | None => return, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | let std_result_path = path![std::result::Result]; | 229 | let core_result_path = path![core::result::Result]; |
230 | 230 | ||
231 | let resolver = self.func.resolver(db.upcast()); | 231 | let resolver = self.func.resolver(db.upcast()); |
232 | let std_result_enum = match resolver.resolve_known_enum(db.upcast(), &std_result_path) { | 232 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
233 | Some(it) => it, | 233 | Some(it) => it, |
234 | _ => return, | 234 | _ => return, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum)); | 237 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
238 | let params = match &mismatch.expected { | 238 | let params = match &mismatch.expected { |
239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, | 239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
240 | parameters | ||
241 | } | ||
240 | _ => return, | 242 | _ => return, |
241 | }; | 243 | }; |
242 | 244 | ||
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index dc77e88e5..3719f76a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -39,8 +39,7 @@ use ra_syntax::SmolStr; | |||
39 | use super::{ | 39 | use super::{ |
40 | primitive::{FloatTy, IntTy}, | 40 | primitive::{FloatTy, IntTy}, |
41 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 41 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
42 | ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, | 42 | InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
43 | TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, | ||
44 | }; | 43 | }; |
45 | use crate::{ | 44 | use crate::{ |
46 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | 45 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, |
@@ -312,12 +311,6 @@ impl<'a> InferenceContext<'a> { | |||
312 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | 311 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { |
313 | match ty { | 312 | match ty { |
314 | Ty::Unknown => self.table.new_type_var(), | 313 | Ty::Unknown => self.table.new_type_var(), |
315 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { | ||
316 | self.table.new_integer_var() | ||
317 | } | ||
318 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { | ||
319 | self.table.new_float_var() | ||
320 | } | ||
321 | _ => ty, | 314 | _ => ty, |
322 | } | 315 | } |
323 | } | 316 | } |
@@ -383,25 +376,6 @@ impl<'a> InferenceContext<'a> { | |||
383 | ) -> Ty { | 376 | ) -> Ty { |
384 | match assoc_ty { | 377 | match assoc_ty { |
385 | Some(res_assoc_ty) => { | 378 | Some(res_assoc_ty) => { |
386 | // FIXME: | ||
387 | // Check if inner_ty is is `impl Trait` and contained input TypeAlias id | ||
388 | // this is a workaround while Chalk assoc type projection doesn't always work yet, | ||
389 | // but once that is fixed I don't think we should keep this | ||
390 | // (we'll probably change how associated types are resolved anyway) | ||
391 | if let Ty::Opaque(ref predicates) = inner_ty { | ||
392 | for p in predicates.iter() { | ||
393 | if let GenericPredicate::Projection(projection) = p { | ||
394 | if projection.projection_ty.associated_ty == res_assoc_ty { | ||
395 | if let ty_app!(_, params) = &projection.ty { | ||
396 | if params.len() == 0 { | ||
397 | return projection.ty.clone(); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | |||
405 | let ty = self.table.new_type_var(); | 379 | let ty = self.table.new_type_var(); |
406 | let builder = Substs::build_for_def(self.db, res_assoc_ty) | 380 | let builder = Substs::build_for_def(self.db, res_assoc_ty) |
407 | .push(inner_ty) | 381 | .push(inner_ty) |
@@ -458,13 +432,13 @@ impl<'a> InferenceContext<'a> { | |||
458 | }; | 432 | }; |
459 | return match resolution { | 433 | return match resolution { |
460 | TypeNs::AdtId(AdtId::StructId(strukt)) => { | 434 | TypeNs::AdtId(AdtId::StructId(strukt)) => { |
461 | let substs = Ty::substs_from_path(&ctx, path, strukt.into()); | 435 | let substs = Ty::substs_from_path(&ctx, path, strukt.into(), true); |
462 | let ty = self.db.ty(strukt.into()); | 436 | let ty = self.db.ty(strukt.into()); |
463 | let ty = self.insert_type_vars(ty.subst(&substs)); | 437 | let ty = self.insert_type_vars(ty.subst(&substs)); |
464 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) | 438 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) |
465 | } | 439 | } |
466 | TypeNs::EnumVariantId(var) => { | 440 | TypeNs::EnumVariantId(var) => { |
467 | let substs = Ty::substs_from_path(&ctx, path, var.into()); | 441 | let substs = Ty::substs_from_path(&ctx, path, var.into(), true); |
468 | let ty = self.db.ty(var.parent.into()); | 442 | let ty = self.db.ty(var.parent.into()); |
469 | let ty = self.insert_type_vars(ty.subst(&substs)); | 443 | let ty = self.insert_type_vars(ty.subst(&substs)); |
470 | forbid_unresolved_segments((ty, Some(var.into())), unresolved) | 444 | forbid_unresolved_segments((ty, Some(var.into())), unresolved) |
@@ -581,13 +555,13 @@ impl<'a> InferenceContext<'a> { | |||
581 | } | 555 | } |
582 | 556 | ||
583 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { | 557 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { |
584 | let path = path![std::iter::IntoIterator]; | 558 | let path = path![core::iter::IntoIterator]; |
585 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 559 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
586 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) | 560 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) |
587 | } | 561 | } |
588 | 562 | ||
589 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | 563 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { |
590 | let path = path![std::ops::Try]; | 564 | let path = path![core::ops::Try]; |
591 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 565 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
592 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | 566 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) |
593 | } | 567 | } |
@@ -613,37 +587,37 @@ impl<'a> InferenceContext<'a> { | |||
613 | } | 587 | } |
614 | 588 | ||
615 | fn resolve_range_full(&self) -> Option<AdtId> { | 589 | fn resolve_range_full(&self) -> Option<AdtId> { |
616 | let path = path![std::ops::RangeFull]; | 590 | let path = path![core::ops::RangeFull]; |
617 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 591 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
618 | Some(struct_.into()) | 592 | Some(struct_.into()) |
619 | } | 593 | } |
620 | 594 | ||
621 | fn resolve_range(&self) -> Option<AdtId> { | 595 | fn resolve_range(&self) -> Option<AdtId> { |
622 | let path = path![std::ops::Range]; | 596 | let path = path![core::ops::Range]; |
623 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 597 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
624 | Some(struct_.into()) | 598 | Some(struct_.into()) |
625 | } | 599 | } |
626 | 600 | ||
627 | fn resolve_range_inclusive(&self) -> Option<AdtId> { | 601 | fn resolve_range_inclusive(&self) -> Option<AdtId> { |
628 | let path = path![std::ops::RangeInclusive]; | 602 | let path = path![core::ops::RangeInclusive]; |
629 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 603 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
630 | Some(struct_.into()) | 604 | Some(struct_.into()) |
631 | } | 605 | } |
632 | 606 | ||
633 | fn resolve_range_from(&self) -> Option<AdtId> { | 607 | fn resolve_range_from(&self) -> Option<AdtId> { |
634 | let path = path![std::ops::RangeFrom]; | 608 | let path = path![core::ops::RangeFrom]; |
635 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 609 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
636 | Some(struct_.into()) | 610 | Some(struct_.into()) |
637 | } | 611 | } |
638 | 612 | ||
639 | fn resolve_range_to(&self) -> Option<AdtId> { | 613 | fn resolve_range_to(&self) -> Option<AdtId> { |
640 | let path = path![std::ops::RangeTo]; | 614 | let path = path![core::ops::RangeTo]; |
641 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 615 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
642 | Some(struct_.into()) | 616 | Some(struct_.into()) |
643 | } | 617 | } |
644 | 618 | ||
645 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | 619 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { |
646 | let path = path![std::ops::RangeToInclusive]; | 620 | let path = path![core::ops::RangeToInclusive]; |
647 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 621 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
648 | Some(struct_.into()) | 622 | Some(struct_.into()) |
649 | } | 623 | } |
@@ -683,8 +657,8 @@ impl InferTy { | |||
683 | fn fallback_value(self) -> Ty { | 657 | fn fallback_value(self) -> Ty { |
684 | match self { | 658 | match self { |
685 | InferTy::TypeVar(..) => Ty::Unknown, | 659 | InferTy::TypeVar(..) => Ty::Unknown, |
686 | InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), | 660 | InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(IntTy::i32())), |
687 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), | 661 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(FloatTy::f64())), |
688 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), | 662 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), |
689 | } | 663 | } |
690 | } | 664 | } |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 4a98e2deb..9fd310f69 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -18,7 +18,7 @@ use crate::{ | |||
18 | traits::InEnvironment, | 18 | traits::InEnvironment, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, Uncertain, | 21 | TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
@@ -426,15 +426,7 @@ impl<'a> InferenceContext<'a> { | |||
426 | match &inner_ty { | 426 | match &inner_ty { |
427 | // Fast path for builtins | 427 | // Fast path for builtins |
428 | Ty::Apply(ApplicationTy { | 428 | Ty::Apply(ApplicationTy { |
429 | ctor: | 429 | ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }), |
430 | TypeCtor::Int(Uncertain::Known(IntTy { | ||
431 | signedness: Signedness::Signed, | ||
432 | .. | ||
433 | })), | ||
434 | .. | ||
435 | }) | ||
436 | | Ty::Apply(ApplicationTy { | ||
437 | ctor: TypeCtor::Int(Uncertain::Unknown), | ||
438 | .. | 430 | .. |
439 | }) | 431 | }) |
440 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) | 432 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) |
@@ -577,9 +569,7 @@ impl<'a> InferenceContext<'a> { | |||
577 | ); | 569 | ); |
578 | self.infer_expr( | 570 | self.infer_expr( |
579 | *repeat, | 571 | *repeat, |
580 | &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( | 572 | &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))), |
581 | IntTy::usize(), | ||
582 | )))), | ||
583 | ); | 573 | ); |
584 | } | 574 | } |
585 | } | 575 | } |
@@ -592,13 +582,19 @@ impl<'a> InferenceContext<'a> { | |||
592 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) | 582 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) |
593 | } | 583 | } |
594 | Literal::ByteString(..) => { | 584 | Literal::ByteString(..) => { |
595 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); | 585 | let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8())); |
596 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); | 586 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); |
597 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) | 587 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) |
598 | } | 588 | } |
599 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | 589 | Literal::Char(..) => Ty::simple(TypeCtor::Char), |
600 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), | 590 | Literal::Int(_v, ty) => match ty { |
601 | Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), | 591 | Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())), |
592 | None => self.table.new_integer_var(), | ||
593 | }, | ||
594 | Literal::Float(_v, ty) => match ty { | ||
595 | Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())), | ||
596 | None => self.table.new_float_var(), | ||
597 | }, | ||
602 | }, | 598 | }, |
603 | }; | 599 | }; |
604 | // use a new type variable if we got Ty::Unknown here | 600 | // use a new type variable if we got Ty::Unknown here |
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1c2e56fb0..1ad0d8397 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -95,7 +95,7 @@ impl<'a> InferenceContext<'a> { | |||
95 | // self_subst is just for the parent | 95 | // self_subst is just for the parent |
96 | let parent_substs = self_subst.unwrap_or_else(Substs::empty); | 96 | let parent_substs = self_subst.unwrap_or_else(Substs::empty); |
97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | 97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); |
98 | let substs = Ty::substs_from_path(&ctx, path, typable); | 98 | let substs = Ty::substs_from_path(&ctx, path, typable, true); |
99 | let full_substs = Substs::builder(substs.len()) | 99 | let full_substs = Substs::builder(substs.len()) |
100 | .use_parent_substs(&parent_substs) | 100 | .use_parent_substs(&parent_substs) |
101 | .fill(substs.0[parent_substs.len()..].iter().cloned()) | 101 | .fill(substs.0[parent_substs.len()..].iter().cloned()) |
@@ -141,6 +141,7 @@ impl<'a> InferenceContext<'a> { | |||
141 | def, | 141 | def, |
142 | resolved_segment, | 142 | resolved_segment, |
143 | remaining_segments_for_ty, | 143 | remaining_segments_for_ty, |
144 | true, | ||
144 | ); | 145 | ); |
145 | if let Ty::Unknown = ty { | 146 | if let Ty::Unknown = ty { |
146 | return None; | 147 | return None; |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 9fa8d3bdc..2b9372b4b 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -58,7 +58,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; | |||
58 | 58 | ||
59 | use crate::{ | 59 | use crate::{ |
60 | db::HirDatabase, | 60 | db::HirDatabase, |
61 | primitive::{FloatTy, IntTy, Uncertain}, | 61 | primitive::{FloatTy, IntTy}, |
62 | utils::{generics, make_mut_slice, Generics}, | 62 | utils::{generics, make_mut_slice, Generics}, |
63 | }; | 63 | }; |
64 | use display::HirDisplay; | 64 | use display::HirDisplay; |
@@ -87,10 +87,10 @@ pub enum TypeCtor { | |||
87 | Char, | 87 | Char, |
88 | 88 | ||
89 | /// A primitive integer type. For example, `i32`. | 89 | /// A primitive integer type. For example, `i32`. |
90 | Int(Uncertain<IntTy>), | 90 | Int(IntTy), |
91 | 91 | ||
92 | /// A primitive floating-point type. For example, `f64`. | 92 | /// A primitive floating-point type. For example, `f64`. |
93 | Float(Uncertain<FloatTy>), | 93 | Float(FloatTy), |
94 | 94 | ||
95 | /// Structures, enumerations and unions. | 95 | /// Structures, enumerations and unions. |
96 | Adt(AdtId), | 96 | Adt(AdtId), |
@@ -147,6 +147,12 @@ pub enum TypeCtor { | |||
147 | /// an **application type** like `(Iterator::Item)<T>`. | 147 | /// an **application type** like `(Iterator::Item)<T>`. |
148 | AssociatedType(TypeAliasId), | 148 | AssociatedType(TypeAliasId), |
149 | 149 | ||
150 | /// This represents a placeholder for an opaque type in situations where we | ||
151 | /// don't know the hidden type (i.e. currently almost always). This is | ||
152 | /// analogous to the `AssociatedType` type constructor. As with that one, | ||
153 | /// these are only produced by Chalk. | ||
154 | OpaqueType(OpaqueTyId), | ||
155 | |||
150 | /// The type of a specific closure. | 156 | /// The type of a specific closure. |
151 | /// | 157 | /// |
152 | /// The closure signature is stored in a `FnPtr` type in the first type | 158 | /// The closure signature is stored in a `FnPtr` type in the first type |
@@ -194,6 +200,14 @@ impl TypeCtor { | |||
194 | let generic_params = generics(db.upcast(), type_alias.into()); | 200 | let generic_params = generics(db.upcast(), type_alias.into()); |
195 | generic_params.len() | 201 | generic_params.len() |
196 | } | 202 | } |
203 | TypeCtor::OpaqueType(opaque_ty_id) => { | ||
204 | match opaque_ty_id { | ||
205 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | ||
206 | let generic_params = generics(db.upcast(), func.into()); | ||
207 | generic_params.len() | ||
208 | } | ||
209 | } | ||
210 | } | ||
197 | TypeCtor::FnPtr { num_args } => num_args as usize + 1, | 211 | TypeCtor::FnPtr { num_args } => num_args as usize + 1, |
198 | TypeCtor::Tuple { cardinality } => cardinality as usize, | 212 | TypeCtor::Tuple { cardinality } => cardinality as usize, |
199 | } | 213 | } |
@@ -220,6 +234,11 @@ impl TypeCtor { | |||
220 | TypeCtor::AssociatedType(type_alias) => { | 234 | TypeCtor::AssociatedType(type_alias) => { |
221 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) | 235 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) |
222 | } | 236 | } |
237 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { | ||
238 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | ||
239 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) | ||
240 | } | ||
241 | }, | ||
223 | } | 242 | } |
224 | } | 243 | } |
225 | 244 | ||
@@ -241,6 +260,7 @@ impl TypeCtor { | |||
241 | TypeCtor::Adt(adt) => Some(adt.into()), | 260 | TypeCtor::Adt(adt) => Some(adt.into()), |
242 | TypeCtor::FnDef(callable) => Some(callable.into()), | 261 | TypeCtor::FnDef(callable) => Some(callable.into()), |
243 | TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), | 262 | TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), |
263 | TypeCtor::OpaqueType(_impl_trait_id) => None, | ||
244 | } | 264 | } |
245 | } | 265 | } |
246 | } | 266 | } |
@@ -254,6 +274,12 @@ pub struct ApplicationTy { | |||
254 | pub parameters: Substs, | 274 | pub parameters: Substs, |
255 | } | 275 | } |
256 | 276 | ||
277 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
278 | pub struct OpaqueTy { | ||
279 | pub opaque_ty_id: OpaqueTyId, | ||
280 | pub parameters: Substs, | ||
281 | } | ||
282 | |||
257 | /// A "projection" type corresponds to an (unnormalized) | 283 | /// A "projection" type corresponds to an (unnormalized) |
258 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | 284 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the |
259 | /// trait and all its parameters are fully known. | 285 | /// trait and all its parameters are fully known. |
@@ -308,6 +334,12 @@ pub enum Ty { | |||
308 | /// trait and all its parameters are fully known. | 334 | /// trait and all its parameters are fully known. |
309 | Projection(ProjectionTy), | 335 | Projection(ProjectionTy), |
310 | 336 | ||
337 | /// An opaque type (`impl Trait`). | ||
338 | /// | ||
339 | /// This is currently only used for return type impl trait; each instance of | ||
340 | /// `impl Trait` in a return type gets its own ID. | ||
341 | Opaque(OpaqueTy), | ||
342 | |||
311 | /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T) | 343 | /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T) |
312 | /// {}` when we're type-checking the body of that function. In this | 344 | /// {}` when we're type-checking the body of that function. In this |
313 | /// situation, we know this stands for *some* type, but don't know the exact | 345 | /// situation, we know this stands for *some* type, but don't know the exact |
@@ -332,12 +364,6 @@ pub enum Ty { | |||
332 | /// didn't seem worth the overhead yet. | 364 | /// didn't seem worth the overhead yet. |
333 | Dyn(Arc<[GenericPredicate]>), | 365 | Dyn(Arc<[GenericPredicate]>), |
334 | 366 | ||
335 | /// An opaque type (`impl Trait`). | ||
336 | /// | ||
337 | /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for | ||
338 | /// more. | ||
339 | Opaque(Arc<[GenericPredicate]>), | ||
340 | |||
341 | /// A placeholder for a type which could not be computed; this is propagated | 367 | /// A placeholder for a type which could not be computed; this is propagated |
342 | /// to avoid useless error messages. Doubles as a placeholder where type | 368 | /// to avoid useless error messages. Doubles as a placeholder where type |
343 | /// variables are inserted before type checking, since we want to try to | 369 | /// variables are inserted before type checking, since we want to try to |
@@ -490,7 +516,7 @@ impl Deref for Substs { | |||
490 | } | 516 | } |
491 | } | 517 | } |
492 | 518 | ||
493 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 519 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
494 | pub struct Binders<T> { | 520 | pub struct Binders<T> { |
495 | pub num_binders: usize, | 521 | pub num_binders: usize, |
496 | pub value: T, | 522 | pub value: T, |
@@ -534,6 +560,20 @@ impl<T: TypeWalk> Binders<T> { | |||
534 | } | 560 | } |
535 | } | 561 | } |
536 | 562 | ||
563 | impl<T: TypeWalk> TypeWalk for Binders<T> { | ||
564 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
565 | self.value.walk(f); | ||
566 | } | ||
567 | |||
568 | fn walk_mut_binders( | ||
569 | &mut self, | ||
570 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
571 | binders: DebruijnIndex, | ||
572 | ) { | ||
573 | self.value.walk_mut_binders(f, binders.shifted_in()) | ||
574 | } | ||
575 | } | ||
576 | |||
537 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. | 577 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. |
538 | /// Name to be bikeshedded: TraitBound? TraitImplements? | 578 | /// Name to be bikeshedded: TraitBound? TraitImplements? |
539 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 579 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
@@ -947,11 +987,16 @@ impl TypeWalk for Ty { | |||
947 | t.walk(f); | 987 | t.walk(f); |
948 | } | 988 | } |
949 | } | 989 | } |
950 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | 990 | Ty::Dyn(predicates) => { |
951 | for p in predicates.iter() { | 991 | for p in predicates.iter() { |
952 | p.walk(f); | 992 | p.walk(f); |
953 | } | 993 | } |
954 | } | 994 | } |
995 | Ty::Opaque(o_ty) => { | ||
996 | for t in o_ty.parameters.iter() { | ||
997 | t.walk(f); | ||
998 | } | ||
999 | } | ||
955 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 1000 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
956 | } | 1001 | } |
957 | f(self); | 1002 | f(self); |
@@ -969,13 +1014,48 @@ impl TypeWalk for Ty { | |||
969 | Ty::Projection(p_ty) => { | 1014 | Ty::Projection(p_ty) => { |
970 | p_ty.parameters.walk_mut_binders(f, binders); | 1015 | p_ty.parameters.walk_mut_binders(f, binders); |
971 | } | 1016 | } |
972 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | 1017 | Ty::Dyn(predicates) => { |
973 | for p in make_mut_slice(predicates) { | 1018 | for p in make_mut_slice(predicates) { |
974 | p.walk_mut_binders(f, binders.shifted_in()); | 1019 | p.walk_mut_binders(f, binders.shifted_in()); |
975 | } | 1020 | } |
976 | } | 1021 | } |
1022 | Ty::Opaque(o_ty) => { | ||
1023 | o_ty.parameters.walk_mut_binders(f, binders); | ||
1024 | } | ||
977 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 1025 | Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
978 | } | 1026 | } |
979 | f(self, binders); | 1027 | f(self, binders); |
980 | } | 1028 | } |
981 | } | 1029 | } |
1030 | |||
1031 | impl<T: TypeWalk> TypeWalk for Vec<T> { | ||
1032 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
1033 | for t in self { | ||
1034 | t.walk(f); | ||
1035 | } | ||
1036 | } | ||
1037 | fn walk_mut_binders( | ||
1038 | &mut self, | ||
1039 | f: &mut impl FnMut(&mut Ty, DebruijnIndex), | ||
1040 | binders: DebruijnIndex, | ||
1041 | ) { | ||
1042 | for t in self { | ||
1043 | t.walk_mut_binders(f, binders); | ||
1044 | } | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | ||
1049 | pub enum OpaqueTyId { | ||
1050 | ReturnTypeImplTrait(hir_def::FunctionId, u16), | ||
1051 | } | ||
1052 | |||
1053 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
1054 | pub struct ReturnTypeImplTraits { | ||
1055 | pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, | ||
1056 | } | ||
1057 | |||
1058 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
1059 | pub(crate) struct ReturnTypeImplTrait { | ||
1060 | pub(crate) bounds: Binders<Vec<GenericPredicate>>, | ||
1061 | } | ||
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 35ac86a46..42713928f 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -21,8 +21,10 @@ use hir_def::{ | |||
21 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 21 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
22 | UnionId, VariantId, | 22 | UnionId, VariantId, |
23 | }; | 23 | }; |
24 | use hir_expand::name::Name; | ||
24 | use ra_arena::map::ArenaMap; | 25 | use ra_arena::map::ArenaMap; |
25 | use ra_db::CrateId; | 26 | use ra_db::CrateId; |
27 | use test_utils::mark; | ||
26 | 28 | ||
27 | use crate::{ | 29 | use crate::{ |
28 | db::HirDatabase, | 30 | db::HirDatabase, |
@@ -31,10 +33,10 @@ use crate::{ | |||
31 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, | 33 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, |
32 | make_mut_slice, variant_data, | 34 | make_mut_slice, variant_data, |
33 | }, | 35 | }, |
34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, | 36 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig, |
35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | 37 | ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs, |
38 | TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | ||
36 | }; | 39 | }; |
37 | use hir_expand::name::Name; | ||
38 | 40 | ||
39 | #[derive(Debug)] | 41 | #[derive(Debug)] |
40 | pub struct TyLoweringContext<'a> { | 42 | pub struct TyLoweringContext<'a> { |
@@ -47,7 +49,16 @@ pub struct TyLoweringContext<'a> { | |||
47 | /// possible currently, so this should be fine for now. | 49 | /// possible currently, so this should be fine for now. |
48 | pub type_param_mode: TypeParamLoweringMode, | 50 | pub type_param_mode: TypeParamLoweringMode, |
49 | pub impl_trait_mode: ImplTraitLoweringMode, | 51 | pub impl_trait_mode: ImplTraitLoweringMode, |
50 | pub impl_trait_counter: std::cell::Cell<u16>, | 52 | impl_trait_counter: std::cell::Cell<u16>, |
53 | /// When turning `impl Trait` into opaque types, we have to collect the | ||
54 | /// bounds at the same time to get the IDs correct (without becoming too | ||
55 | /// complicated). I don't like using interior mutability (as for the | ||
56 | /// counter), but I've tried and failed to make the lifetimes work for | ||
57 | /// passing around a `&mut TyLoweringContext`. The core problem is that | ||
58 | /// we're grouping the mutable data (the counter and this field) together | ||
59 | /// with the immutable context (the references to the DB and resolver). | ||
60 | /// Splitting this up would be a possible fix. | ||
61 | opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, | ||
51 | } | 62 | } |
52 | 63 | ||
53 | impl<'a> TyLoweringContext<'a> { | 64 | impl<'a> TyLoweringContext<'a> { |
@@ -56,26 +67,42 @@ impl<'a> TyLoweringContext<'a> { | |||
56 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; | 67 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; |
57 | let type_param_mode = TypeParamLoweringMode::Placeholder; | 68 | let type_param_mode = TypeParamLoweringMode::Placeholder; |
58 | let in_binders = DebruijnIndex::INNERMOST; | 69 | let in_binders = DebruijnIndex::INNERMOST; |
59 | Self { db, resolver, in_binders, impl_trait_mode, impl_trait_counter, type_param_mode } | 70 | let opaque_type_data = std::cell::RefCell::new(Vec::new()); |
71 | Self { | ||
72 | db, | ||
73 | resolver, | ||
74 | in_binders, | ||
75 | impl_trait_mode, | ||
76 | impl_trait_counter, | ||
77 | type_param_mode, | ||
78 | opaque_type_data, | ||
79 | } | ||
60 | } | 80 | } |
61 | 81 | ||
62 | pub fn with_shifted_in<T>( | 82 | pub fn with_debruijn<T>( |
63 | &self, | 83 | &self, |
64 | debruijn: DebruijnIndex, | 84 | debruijn: DebruijnIndex, |
65 | f: impl FnOnce(&TyLoweringContext) -> T, | 85 | f: impl FnOnce(&TyLoweringContext) -> T, |
66 | ) -> T { | 86 | ) -> T { |
87 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); | ||
67 | let new_ctx = Self { | 88 | let new_ctx = Self { |
68 | in_binders: self.in_binders.shifted_in_from(debruijn), | 89 | in_binders: debruijn, |
69 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), | 90 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), |
91 | opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), | ||
70 | ..*self | 92 | ..*self |
71 | }; | 93 | }; |
72 | let result = f(&new_ctx); | 94 | let result = f(&new_ctx); |
73 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); | 95 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); |
96 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); | ||
74 | result | 97 | result |
75 | } | 98 | } |
76 | 99 | ||
77 | pub fn shifted_in(self, debruijn: DebruijnIndex) -> Self { | 100 | pub fn with_shifted_in<T>( |
78 | Self { in_binders: self.in_binders.shifted_in_from(debruijn), ..self } | 101 | &self, |
102 | debruijn: DebruijnIndex, | ||
103 | f: impl FnOnce(&TyLoweringContext) -> T, | ||
104 | ) -> T { | ||
105 | self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) | ||
79 | } | 106 | } |
80 | 107 | ||
81 | pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { | 108 | pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { |
@@ -167,20 +194,44 @@ impl Ty { | |||
167 | TypeRef::ImplTrait(bounds) => { | 194 | TypeRef::ImplTrait(bounds) => { |
168 | match ctx.impl_trait_mode { | 195 | match ctx.impl_trait_mode { |
169 | ImplTraitLoweringMode::Opaque => { | 196 | ImplTraitLoweringMode::Opaque => { |
170 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | 197 | let idx = ctx.impl_trait_counter.get(); |
171 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 198 | ctx.impl_trait_counter.set(idx + 1); |
172 | bounds | 199 | |
173 | .iter() | 200 | assert!(idx as usize == ctx.opaque_type_data.borrow().len()); |
174 | .flat_map(|b| { | 201 | // this dance is to make sure the data is in the right |
175 | GenericPredicate::from_type_bound(ctx, b, self_ty.clone()) | 202 | // place even if we encounter more opaque types while |
176 | }) | 203 | // lowering the bounds |
177 | .collect() | 204 | ctx.opaque_type_data |
178 | }); | 205 | .borrow_mut() |
179 | Ty::Opaque(predicates) | 206 | .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); |
207 | // We don't want to lower the bounds inside the binders | ||
208 | // we're currently in, because they don't end up inside | ||
209 | // those binders. E.g. when we have `impl Trait<impl | ||
210 | // OtherTrait<T>>`, the `impl OtherTrait<T>` can't refer | ||
211 | // to the self parameter from `impl Trait`, and the | ||
212 | // bounds aren't actually stored nested within each | ||
213 | // other, but separately. So if the `T` refers to a type | ||
214 | // parameter of the outer function, it's just one binder | ||
215 | // away instead of two. | ||
216 | let actual_opaque_type_data = ctx | ||
217 | .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { | ||
218 | ReturnTypeImplTrait::from_hir(ctx, &bounds) | ||
219 | }); | ||
220 | ctx.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data; | ||
221 | |||
222 | let func = match ctx.resolver.generic_def() { | ||
223 | Some(GenericDefId::FunctionId(f)) => f, | ||
224 | _ => panic!("opaque impl trait lowering in non-function"), | ||
225 | }; | ||
226 | let impl_trait_id = OpaqueTyId::ReturnTypeImplTrait(func, idx); | ||
227 | let generics = generics(ctx.db.upcast(), func.into()); | ||
228 | let parameters = Substs::bound_vars(&generics, ctx.in_binders); | ||
229 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
180 | } | 230 | } |
181 | ImplTraitLoweringMode::Param => { | 231 | ImplTraitLoweringMode::Param => { |
182 | let idx = ctx.impl_trait_counter.get(); | 232 | let idx = ctx.impl_trait_counter.get(); |
183 | ctx.impl_trait_counter.set(idx + 1); | 233 | // FIXME we're probably doing something wrong here |
234 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
184 | if let Some(def) = ctx.resolver.generic_def() { | 235 | if let Some(def) = ctx.resolver.generic_def() { |
185 | let generics = generics(ctx.db.upcast(), def); | 236 | let generics = generics(ctx.db.upcast(), def); |
186 | let param = generics | 237 | let param = generics |
@@ -197,7 +248,8 @@ impl Ty { | |||
197 | } | 248 | } |
198 | ImplTraitLoweringMode::Variable => { | 249 | ImplTraitLoweringMode::Variable => { |
199 | let idx = ctx.impl_trait_counter.get(); | 250 | let idx = ctx.impl_trait_counter.get(); |
200 | ctx.impl_trait_counter.set(idx + 1); | 251 | // FIXME we're probably doing something wrong here |
252 | ctx.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16); | ||
201 | let (parent_params, self_params, list_params, _impl_trait_params) = | 253 | let (parent_params, self_params, list_params, _impl_trait_params) = |
202 | if let Some(def) = ctx.resolver.generic_def() { | 254 | if let Some(def) = ctx.resolver.generic_def() { |
203 | let generics = generics(ctx.db.upcast(), def); | 255 | let generics = generics(ctx.db.upcast(), def); |
@@ -271,6 +323,7 @@ impl Ty { | |||
271 | resolution: TypeNs, | 323 | resolution: TypeNs, |
272 | resolved_segment: PathSegment<'_>, | 324 | resolved_segment: PathSegment<'_>, |
273 | remaining_segments: PathSegments<'_>, | 325 | remaining_segments: PathSegments<'_>, |
326 | infer_args: bool, | ||
274 | ) -> (Ty, Option<TypeNs>) { | 327 | ) -> (Ty, Option<TypeNs>) { |
275 | let ty = match resolution { | 328 | let ty = match resolution { |
276 | TypeNs::TraitId(trait_) => { | 329 | TypeNs::TraitId(trait_) => { |
@@ -348,9 +401,15 @@ impl Ty { | |||
348 | ctx.db.ty(adt.into()).subst(&substs) | 401 | ctx.db.ty(adt.into()).subst(&substs) |
349 | } | 402 | } |
350 | 403 | ||
351 | TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 404 | TypeNs::AdtId(it) => { |
352 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 405 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) |
353 | TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 406 | } |
407 | TypeNs::BuiltinType(it) => { | ||
408 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
409 | } | ||
410 | TypeNs::TypeAliasId(it) => { | ||
411 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
412 | } | ||
354 | // FIXME: report error | 413 | // FIXME: report error |
355 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), | 414 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), |
356 | }; | 415 | }; |
@@ -376,7 +435,13 @@ impl Ty { | |||
376 | ), | 435 | ), |
377 | Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), | 436 | Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), |
378 | }; | 437 | }; |
379 | Ty::from_partly_resolved_hir_path(ctx, resolution, resolved_segment, remaining_segments) | 438 | Ty::from_partly_resolved_hir_path( |
439 | ctx, | ||
440 | resolution, | ||
441 | resolved_segment, | ||
442 | remaining_segments, | ||
443 | false, | ||
444 | ) | ||
380 | } | 445 | } |
381 | 446 | ||
382 | fn select_associated_type( | 447 | fn select_associated_type( |
@@ -422,13 +487,14 @@ impl Ty { | |||
422 | ctx: &TyLoweringContext<'_>, | 487 | ctx: &TyLoweringContext<'_>, |
423 | segment: PathSegment<'_>, | 488 | segment: PathSegment<'_>, |
424 | typable: TyDefId, | 489 | typable: TyDefId, |
490 | infer_args: bool, | ||
425 | ) -> Ty { | 491 | ) -> Ty { |
426 | let generic_def = match typable { | 492 | let generic_def = match typable { |
427 | TyDefId::BuiltinType(_) => None, | 493 | TyDefId::BuiltinType(_) => None, |
428 | TyDefId::AdtId(it) => Some(it.into()), | 494 | TyDefId::AdtId(it) => Some(it.into()), |
429 | TyDefId::TypeAliasId(it) => Some(it.into()), | 495 | TyDefId::TypeAliasId(it) => Some(it.into()), |
430 | }; | 496 | }; |
431 | let substs = substs_from_path_segment(ctx, segment, generic_def, false); | 497 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); |
432 | ctx.db.ty(typable).subst(&substs) | 498 | ctx.db.ty(typable).subst(&substs) |
433 | } | 499 | } |
434 | 500 | ||
@@ -441,6 +507,7 @@ impl Ty { | |||
441 | // `ValueTyDefId` is just a convenient way to pass generics and | 507 | // `ValueTyDefId` is just a convenient way to pass generics and |
442 | // special-case enum variants | 508 | // special-case enum variants |
443 | resolved: ValueTyDefId, | 509 | resolved: ValueTyDefId, |
510 | infer_args: bool, | ||
444 | ) -> Substs { | 511 | ) -> Substs { |
445 | let last = path.segments().last().expect("path should have at least one segment"); | 512 | let last = path.segments().last().expect("path should have at least one segment"); |
446 | let (segment, generic_def) = match resolved { | 513 | let (segment, generic_def) = match resolved { |
@@ -463,22 +530,27 @@ impl Ty { | |||
463 | (segment, Some(var.parent.into())) | 530 | (segment, Some(var.parent.into())) |
464 | } | 531 | } |
465 | }; | 532 | }; |
466 | substs_from_path_segment(ctx, segment, generic_def, false) | 533 | substs_from_path_segment(ctx, segment, generic_def, infer_args) |
467 | } | 534 | } |
468 | } | 535 | } |
469 | 536 | ||
470 | pub(super) fn substs_from_path_segment( | 537 | fn substs_from_path_segment( |
471 | ctx: &TyLoweringContext<'_>, | 538 | ctx: &TyLoweringContext<'_>, |
472 | segment: PathSegment<'_>, | 539 | segment: PathSegment<'_>, |
473 | def_generic: Option<GenericDefId>, | 540 | def_generic: Option<GenericDefId>, |
474 | _add_self_param: bool, | 541 | infer_args: bool, |
475 | ) -> Substs { | 542 | ) -> Substs { |
476 | let mut substs = Vec::new(); | 543 | let mut substs = Vec::new(); |
477 | let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); | 544 | let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); |
478 | 545 | ||
479 | let (parent_params, self_params, type_params, impl_trait_params) = | 546 | let (parent_params, self_params, type_params, impl_trait_params) = |
480 | def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); | 547 | def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); |
548 | let total_len = parent_params + self_params + type_params + impl_trait_params; | ||
549 | |||
481 | substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); | 550 | substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); |
551 | |||
552 | let mut had_explicit_args = false; | ||
553 | |||
482 | if let Some(generic_args) = &segment.args_and_bindings { | 554 | if let Some(generic_args) = &segment.args_and_bindings { |
483 | if !generic_args.has_self_type { | 555 | if !generic_args.has_self_type { |
484 | substs.extend(iter::repeat(Ty::Unknown).take(self_params)); | 556 | substs.extend(iter::repeat(Ty::Unknown).take(self_params)); |
@@ -490,31 +562,35 @@ pub(super) fn substs_from_path_segment( | |||
490 | for arg in generic_args.args.iter().skip(skip).take(expected_num) { | 562 | for arg in generic_args.args.iter().skip(skip).take(expected_num) { |
491 | match arg { | 563 | match arg { |
492 | GenericArg::Type(type_ref) => { | 564 | GenericArg::Type(type_ref) => { |
565 | had_explicit_args = true; | ||
493 | let ty = Ty::from_hir(ctx, type_ref); | 566 | let ty = Ty::from_hir(ctx, type_ref); |
494 | substs.push(ty); | 567 | substs.push(ty); |
495 | } | 568 | } |
496 | } | 569 | } |
497 | } | 570 | } |
498 | } | 571 | } |
499 | let total_len = parent_params + self_params + type_params + impl_trait_params; | ||
500 | // add placeholders for args that were not provided | ||
501 | for _ in substs.len()..total_len { | ||
502 | substs.push(Ty::Unknown); | ||
503 | } | ||
504 | assert_eq!(substs.len(), total_len); | ||
505 | 572 | ||
506 | // handle defaults | 573 | // handle defaults. In expression or pattern path segments without |
507 | if let Some(def_generic) = def_generic { | 574 | // explicitly specified type arguments, missing type arguments are inferred |
508 | let default_substs = ctx.db.generic_defaults(def_generic); | 575 | // (i.e. defaults aren't used). |
509 | assert_eq!(substs.len(), default_substs.len()); | 576 | if !infer_args || had_explicit_args { |
577 | if let Some(def_generic) = def_generic { | ||
578 | let default_substs = ctx.db.generic_defaults(def_generic); | ||
579 | assert_eq!(total_len, default_substs.len()); | ||
510 | 580 | ||
511 | for (i, default_ty) in default_substs.iter().enumerate() { | 581 | for default_ty in default_substs.iter().skip(substs.len()) { |
512 | if substs[i] == Ty::Unknown { | 582 | substs.push(default_ty.clone()); |
513 | substs[i] = default_ty.clone(); | ||
514 | } | 583 | } |
515 | } | 584 | } |
516 | } | 585 | } |
517 | 586 | ||
587 | // add placeholders for args that were not provided | ||
588 | // FIXME: emit diagnostics in contexts where this is not allowed | ||
589 | for _ in substs.len()..total_len { | ||
590 | substs.push(Ty::Unknown); | ||
591 | } | ||
592 | assert_eq!(substs.len(), total_len); | ||
593 | |||
518 | Substs(substs.into()) | 594 | Substs(substs.into()) |
519 | } | 595 | } |
520 | 596 | ||
@@ -563,9 +639,7 @@ impl TraitRef { | |||
563 | segment: PathSegment<'_>, | 639 | segment: PathSegment<'_>, |
564 | resolved: TraitId, | 640 | resolved: TraitId, |
565 | ) -> Substs { | 641 | ) -> Substs { |
566 | let has_self_param = | 642 | substs_from_path_segment(ctx, segment, Some(resolved.into()), false) |
567 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); | ||
568 | substs_from_path_segment(ctx, segment, Some(resolved.into()), !has_self_param) | ||
569 | } | 643 | } |
570 | 644 | ||
571 | pub(crate) fn from_type_bound( | 645 | pub(crate) fn from_type_bound( |
@@ -663,6 +737,30 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
663 | }) | 737 | }) |
664 | } | 738 | } |
665 | 739 | ||
740 | impl ReturnTypeImplTrait { | ||
741 | fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { | ||
742 | mark::hit!(lower_rpit); | ||
743 | let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | ||
744 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | ||
745 | bounds | ||
746 | .iter() | ||
747 | .flat_map(|b| GenericPredicate::from_type_bound(ctx, b, self_ty.clone())) | ||
748 | .collect() | ||
749 | }); | ||
750 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } | ||
751 | } | ||
752 | } | ||
753 | |||
754 | fn count_impl_traits(type_ref: &TypeRef) -> usize { | ||
755 | let mut count = 0; | ||
756 | type_ref.walk(&mut |type_ref| { | ||
757 | if matches!(type_ref, TypeRef::ImplTrait(_)) { | ||
758 | count += 1; | ||
759 | } | ||
760 | }); | ||
761 | count | ||
762 | } | ||
763 | |||
666 | /// Build the signature of a callable item (function, struct or enum variant). | 764 | /// Build the signature of a callable item (function, struct or enum variant). |
667 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | 765 | pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { |
668 | match def { | 766 | match def { |
@@ -864,7 +962,9 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | |||
864 | .with_impl_trait_mode(ImplTraitLoweringMode::Variable) | 962 | .with_impl_trait_mode(ImplTraitLoweringMode::Variable) |
865 | .with_type_param_mode(TypeParamLoweringMode::Variable); | 963 | .with_type_param_mode(TypeParamLoweringMode::Variable); |
866 | let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); | 964 | let params = data.params.iter().map(|tr| Ty::from_hir(&ctx_params, tr)).collect::<Vec<_>>(); |
867 | let ctx_ret = ctx_params.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); | 965 | let ctx_ret = TyLoweringContext::new(db, &resolver) |
966 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
967 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
868 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); | 968 | let ret = Ty::from_hir(&ctx_ret, &data.ret_type); |
869 | let generics = generics(db.upcast(), def.into()); | 969 | let generics = generics(db.upcast(), def.into()); |
870 | let num_binders = generics.len(); | 970 | let num_binders = generics.len(); |
@@ -1084,3 +1184,25 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< | |||
1084 | TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, | 1184 | TraitRef::from_hir(&ctx, target_trait, Some(self_ty.value))?, |
1085 | )) | 1185 | )) |
1086 | } | 1186 | } |
1187 | |||
1188 | pub(crate) fn return_type_impl_traits( | ||
1189 | db: &impl HirDatabase, | ||
1190 | def: hir_def::FunctionId, | ||
1191 | ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { | ||
1192 | // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe | ||
1193 | let data = db.function_data(def); | ||
1194 | let resolver = def.resolver(db.upcast()); | ||
1195 | let ctx_ret = TyLoweringContext::new(db, &resolver) | ||
1196 | .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) | ||
1197 | .with_type_param_mode(TypeParamLoweringMode::Variable); | ||
1198 | let _ret = Ty::from_hir(&ctx_ret, &data.ret_type); | ||
1199 | let generics = generics(db.upcast(), def.into()); | ||
1200 | let num_binders = generics.len(); | ||
1201 | let return_type_impl_traits = | ||
1202 | ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; | ||
1203 | if return_type_impl_traits.impl_traits.is_empty() { | ||
1204 | None | ||
1205 | } else { | ||
1206 | Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) | ||
1207 | } | ||
1208 | } | ||
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e19628fdf..e83b39456 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -16,12 +16,8 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
16 | 16 | ||
17 | use super::Substs; | 17 | use super::Substs; |
18 | use crate::{ | 18 | use crate::{ |
19 | autoderef, | 19 | autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, |
20 | db::HirDatabase, | 20 | Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
21 | primitive::{FloatBitness, Uncertain}, | ||
22 | utils::all_super_traits, | ||
23 | ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, | ||
24 | TypeCtor, TypeWalk, | ||
25 | }; | 21 | }; |
26 | 22 | ||
27 | /// This is used as a key for indexing impls. | 23 | /// This is used as a key for indexing impls. |
@@ -147,12 +143,12 @@ impl Ty { | |||
147 | } | 143 | } |
148 | TypeCtor::Bool => lang_item_crate!("bool"), | 144 | TypeCtor::Bool => lang_item_crate!("bool"), |
149 | TypeCtor::Char => lang_item_crate!("char"), | 145 | TypeCtor::Char => lang_item_crate!("char"), |
150 | TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { | 146 | TypeCtor::Float(f) => match f.bitness { |
151 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) | 147 | // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) |
152 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), | 148 | FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"), |
153 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), | 149 | FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"), |
154 | }, | 150 | }, |
155 | TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()), | 151 | TypeCtor::Int(i) => lang_item_crate!(i.ty_to_string()), |
156 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), | 152 | TypeCtor::Str => lang_item_crate!("str_alloc", "str"), |
157 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), | 153 | TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"), |
158 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), | 154 | TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"), |
diff --git a/crates/ra_hir_ty/src/primitive.rs b/crates/ra_hir_ty/src/primitive.rs index 02a8179d9..37966b709 100644 --- a/crates/ra_hir_ty/src/primitive.rs +++ b/crates/ra_hir_ty/src/primitive.rs | |||
@@ -7,42 +7,6 @@ use std::fmt; | |||
7 | 7 | ||
8 | pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness}; | 8 | pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, FloatBitness, IntBitness, Signedness}; |
9 | 9 | ||
10 | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] | ||
11 | pub enum Uncertain<T> { | ||
12 | Unknown, | ||
13 | Known(T), | ||
14 | } | ||
15 | |||
16 | impl From<IntTy> for Uncertain<IntTy> { | ||
17 | fn from(ty: IntTy) -> Self { | ||
18 | Uncertain::Known(ty) | ||
19 | } | ||
20 | } | ||
21 | |||
22 | impl fmt::Display for Uncertain<IntTy> { | ||
23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
24 | match *self { | ||
25 | Uncertain::Unknown => write!(f, "{{integer}}"), | ||
26 | Uncertain::Known(ty) => write!(f, "{}", ty), | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | |||
31 | impl From<FloatTy> for Uncertain<FloatTy> { | ||
32 | fn from(ty: FloatTy) -> Self { | ||
33 | Uncertain::Known(ty) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | impl fmt::Display for Uncertain<FloatTy> { | ||
38 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
39 | match *self { | ||
40 | Uncertain::Unknown => write!(f, "{{float}}"), | ||
41 | Uncertain::Known(ty) => write!(f, "{}", ty), | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | #[derive(Copy, Clone, Eq, PartialEq, Hash)] | 10 | #[derive(Copy, Clone, Eq, PartialEq, Hash)] |
47 | pub struct IntTy { | 11 | pub struct IntTy { |
48 | pub signedness: Signedness, | 12 | pub signedness: Signedness, |
@@ -173,21 +137,3 @@ impl From<BuiltinFloat> for FloatTy { | |||
173 | FloatTy { bitness: t.bitness } | 137 | FloatTy { bitness: t.bitness } |
174 | } | 138 | } |
175 | } | 139 | } |
176 | |||
177 | impl From<Option<BuiltinInt>> for Uncertain<IntTy> { | ||
178 | fn from(t: Option<BuiltinInt>) -> Self { | ||
179 | match t { | ||
180 | None => Uncertain::Unknown, | ||
181 | Some(t) => Uncertain::Known(t.into()), | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | impl From<Option<BuiltinFloat>> for Uncertain<FloatTy> { | ||
187 | fn from(t: Option<BuiltinFloat>) -> Self { | ||
188 | match t { | ||
189 | None => Uncertain::Unknown, | ||
190 | Some(t) => Uncertain::Known(t.into()), | ||
191 | } | ||
192 | } | ||
193 | } | ||
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 8498d3d96..ad04e3e0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -7,9 +7,8 @@ use std::{ | |||
7 | 7 | ||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; |
10 | use ra_db::{ | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase, Upcast, | 11 | use rustc_hash::FxHashSet; |
12 | }; | ||
13 | use stdx::format_to; | 12 | use stdx::format_to; |
14 | 13 | ||
15 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | 14 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; |
@@ -72,23 +71,12 @@ impl FileLoader for TestDB { | |||
72 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 71 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
73 | FileLoaderDelegate(self).file_text(file_id) | 72 | FileLoaderDelegate(self).file_text(file_id) |
74 | } | 73 | } |
75 | fn resolve_relative_path( | 74 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
76 | &self, | 75 | FileLoaderDelegate(self).resolve_path(anchor, path) |
77 | anchor: FileId, | ||
78 | relative_path: &RelativePath, | ||
79 | ) -> Option<FileId> { | ||
80 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
81 | } | 76 | } |
82 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 77 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
83 | FileLoaderDelegate(self).relevant_crates(file_id) | 78 | FileLoaderDelegate(self).relevant_crates(file_id) |
84 | } | 79 | } |
85 | fn resolve_extern_path( | ||
86 | &self, | ||
87 | extern_id: ra_db::ExternSourceId, | ||
88 | relative_path: &RelativePath, | ||
89 | ) -> Option<FileId> { | ||
90 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
91 | } | ||
92 | } | 80 | } |
93 | 81 | ||
94 | impl TestDB { | 82 | impl TestDB { |
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs index 4088b1d22..5dfa0a014 100644 --- a/crates/ra_hir_ty/src/tests/display_source_code.rs +++ b/crates/ra_hir_ty/src/tests/display_source_code.rs | |||
@@ -29,7 +29,7 @@ fn omit_default_type_parameters() { | |||
29 | //- /main.rs | 29 | //- /main.rs |
30 | struct Foo<T = u8> { t: T } | 30 | struct Foo<T = u8> { t: T } |
31 | fn main() { | 31 | fn main() { |
32 | let foo = Foo { t: 5 }; | 32 | let foo = Foo { t: 5u8 }; |
33 | foo<|>; | 33 | foo<|>; |
34 | } | 34 | } |
35 | ", | 35 | ", |
@@ -41,7 +41,7 @@ fn omit_default_type_parameters() { | |||
41 | //- /main.rs | 41 | //- /main.rs |
42 | struct Foo<K, T = u8> { k: K, t: T } | 42 | struct Foo<K, T = u8> { k: K, t: T } |
43 | fn main() { | 43 | fn main() { |
44 | let foo = Foo { k: 400, t: 5 }; | 44 | let foo = Foo { k: 400, t: 5u8 }; |
45 | foo<|>; | 45 | foo<|>; |
46 | } | 46 | } |
47 | ", | 47 | ", |
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 558a70022..804297315 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -184,60 +184,6 @@ fn test() { | |||
184 | } | 184 | } |
185 | 185 | ||
186 | #[test] | 186 | #[test] |
187 | fn infer_associated_method_generics_with_default_param() { | ||
188 | assert_snapshot!( | ||
189 | infer(r#" | ||
190 | struct Gen<T=u32> { | ||
191 | val: T | ||
192 | } | ||
193 | |||
194 | impl<T> Gen<T> { | ||
195 | pub fn make() -> Gen<T> { | ||
196 | loop { } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn test() { | ||
201 | let a = Gen::make(); | ||
202 | } | ||
203 | "#), | ||
204 | @r###" | ||
205 | 80..104 '{ ... }': Gen<T> | ||
206 | 90..98 'loop { }': ! | ||
207 | 95..98 '{ }': () | ||
208 | 118..146 '{ ...e(); }': () | ||
209 | 128..129 'a': Gen<u32> | ||
210 | 132..141 'Gen::make': fn make<u32>() -> Gen<u32> | ||
211 | 132..143 'Gen::make()': Gen<u32> | ||
212 | "### | ||
213 | ); | ||
214 | } | ||
215 | |||
216 | #[test] | ||
217 | fn infer_associated_method_generics_with_default_tuple_param() { | ||
218 | let t = type_at( | ||
219 | r#" | ||
220 | //- /main.rs | ||
221 | struct Gen<T=()> { | ||
222 | val: T | ||
223 | } | ||
224 | |||
225 | impl<T> Gen<T> { | ||
226 | pub fn make() -> Gen<T> { | ||
227 | loop { } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | fn test() { | ||
232 | let a = Gen::make(); | ||
233 | a.val<|>; | ||
234 | } | ||
235 | "#, | ||
236 | ); | ||
237 | assert_eq!(t, "()"); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn infer_associated_method_generics_without_args() { | 187 | fn infer_associated_method_generics_without_args() { |
242 | assert_snapshot!( | 188 | assert_snapshot!( |
243 | infer(r#" | 189 | infer(r#" |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 88309157b..37659cd02 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -95,7 +95,7 @@ fn foo() { | |||
95 | fn infer_ranges() { | 95 | fn infer_ranges() { |
96 | let (db, pos) = TestDB::with_position( | 96 | let (db, pos) = TestDB::with_position( |
97 | r#" | 97 | r#" |
98 | //- /main.rs crate:main deps:std | 98 | //- /main.rs crate:main deps:core |
99 | fn test() { | 99 | fn test() { |
100 | let a = ..; | 100 | let a = ..; |
101 | let b = 1..; | 101 | let b = 1..; |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | t<|>; | 108 | t<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | #[prelude_import] use prelude::*; | 112 | #[prelude_import] use prelude::*; |
113 | mod prelude {} | 113 | mod prelude {} |
114 | 114 | ||
@@ -1997,3 +1997,111 @@ fn foo() { | |||
1997 | "### | 1997 | "### |
1998 | ); | 1998 | ); |
1999 | } | 1999 | } |
2000 | |||
2001 | #[test] | ||
2002 | fn generic_default() { | ||
2003 | assert_snapshot!( | ||
2004 | infer(r#" | ||
2005 | struct Thing<T = ()> { t: T } | ||
2006 | enum OtherThing<T = ()> { | ||
2007 | One { t: T }, | ||
2008 | Two(T), | ||
2009 | } | ||
2010 | |||
2011 | fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) { | ||
2012 | t1.t; | ||
2013 | t3.t; | ||
2014 | match t2 { | ||
2015 | OtherThing::One { t } => { t; }, | ||
2016 | OtherThing::Two(t) => { t; }, | ||
2017 | } | ||
2018 | match t4 { | ||
2019 | OtherThing::One { t } => { t; }, | ||
2020 | OtherThing::Two(t) => { t; }, | ||
2021 | } | ||
2022 | } | ||
2023 | "#), | ||
2024 | @r###" | ||
2025 | 98..100 't1': Thing<()> | ||
2026 | 109..111 't2': OtherThing<()> | ||
2027 | 125..127 't3': Thing<i32> | ||
2028 | 141..143 't4': OtherThing<i32> | ||
2029 | 162..385 '{ ... } }': () | ||
2030 | 168..170 't1': Thing<()> | ||
2031 | 168..172 't1.t': () | ||
2032 | 178..180 't3': Thing<i32> | ||
2033 | 178..182 't3.t': i32 | ||
2034 | 188..283 'match ... }': () | ||
2035 | 194..196 't2': OtherThing<()> | ||
2036 | 207..228 'OtherT... { t }': OtherThing<()> | ||
2037 | 225..226 't': () | ||
2038 | 232..238 '{ t; }': () | ||
2039 | 234..235 't': () | ||
2040 | 248..266 'OtherT...Two(t)': OtherThing<()> | ||
2041 | 264..265 't': () | ||
2042 | 270..276 '{ t; }': () | ||
2043 | 272..273 't': () | ||
2044 | 288..383 'match ... }': () | ||
2045 | 294..296 't4': OtherThing<i32> | ||
2046 | 307..328 'OtherT... { t }': OtherThing<i32> | ||
2047 | 325..326 't': i32 | ||
2048 | 332..338 '{ t; }': () | ||
2049 | 334..335 't': i32 | ||
2050 | 348..366 'OtherT...Two(t)': OtherThing<i32> | ||
2051 | 364..365 't': i32 | ||
2052 | 370..376 '{ t; }': () | ||
2053 | 372..373 't': i32 | ||
2054 | "### | ||
2055 | ); | ||
2056 | } | ||
2057 | |||
2058 | #[test] | ||
2059 | fn generic_default_in_struct_literal() { | ||
2060 | assert_snapshot!( | ||
2061 | infer(r#" | ||
2062 | struct Thing<T = ()> { t: T } | ||
2063 | enum OtherThing<T = ()> { | ||
2064 | One { t: T }, | ||
2065 | Two(T), | ||
2066 | } | ||
2067 | |||
2068 | fn test() { | ||
2069 | let x = Thing { t: loop {} }; | ||
2070 | let y = Thing { t: () }; | ||
2071 | let z = Thing { t: 1i32 }; | ||
2072 | if let Thing { t } = z { | ||
2073 | t; | ||
2074 | } | ||
2075 | |||
2076 | let a = OtherThing::One { t: 1i32 }; | ||
2077 | let b = OtherThing::Two(1i32); | ||
2078 | } | ||
2079 | "#), | ||
2080 | @r###" | ||
2081 | 100..320 '{ ...32); }': () | ||
2082 | 110..111 'x': Thing<!> | ||
2083 | 114..134 'Thing ...p {} }': Thing<!> | ||
2084 | 125..132 'loop {}': ! | ||
2085 | 130..132 '{}': () | ||
2086 | 144..145 'y': Thing<()> | ||
2087 | 148..163 'Thing { t: () }': Thing<()> | ||
2088 | 159..161 '()': () | ||
2089 | 173..174 'z': Thing<i32> | ||
2090 | 177..194 'Thing ...1i32 }': Thing<i32> | ||
2091 | 188..192 '1i32': i32 | ||
2092 | 200..241 'if let... }': () | ||
2093 | 207..218 'Thing { t }': Thing<i32> | ||
2094 | 215..216 't': i32 | ||
2095 | 221..222 'z': Thing<i32> | ||
2096 | 223..241 '{ ... }': () | ||
2097 | 233..234 't': i32 | ||
2098 | 251..252 'a': OtherThing<i32> | ||
2099 | 255..282 'OtherT...1i32 }': OtherThing<i32> | ||
2100 | 276..280 '1i32': i32 | ||
2101 | 292..293 'b': OtherThing<i32> | ||
2102 | 296..311 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32> | ||
2103 | 296..317 'OtherT...(1i32)': OtherThing<i32> | ||
2104 | 312..316 '1i32': i32 | ||
2105 | "### | ||
2106 | ); | ||
2107 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e8778d419..e81193a3c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -10,7 +10,7 @@ use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | |||
10 | fn infer_await() { | 10 | fn infer_await() { |
11 | let (db, pos) = TestDB::with_position( | 11 | let (db, pos) = TestDB::with_position( |
12 | r#" | 12 | r#" |
13 | //- /main.rs crate:main deps:std | 13 | //- /main.rs crate:main deps:core |
14 | 14 | ||
15 | struct IntFuture; | 15 | struct IntFuture; |
16 | 16 | ||
@@ -24,7 +24,7 @@ fn test() { | |||
24 | v<|>; | 24 | v<|>; |
25 | } | 25 | } |
26 | 26 | ||
27 | //- /std.rs crate:std | 27 | //- /core.rs crate:core |
28 | #[prelude_import] use future::*; | 28 | #[prelude_import] use future::*; |
29 | mod future { | 29 | mod future { |
30 | #[lang = "future_trait"] | 30 | #[lang = "future_trait"] |
@@ -42,7 +42,7 @@ mod future { | |||
42 | fn infer_async() { | 42 | fn infer_async() { |
43 | let (db, pos) = TestDB::with_position( | 43 | let (db, pos) = TestDB::with_position( |
44 | r#" | 44 | r#" |
45 | //- /main.rs crate:main deps:std | 45 | //- /main.rs crate:main deps:core |
46 | 46 | ||
47 | async fn foo() -> u64 { | 47 | async fn foo() -> u64 { |
48 | 128 | 48 | 128 |
@@ -54,7 +54,7 @@ fn test() { | |||
54 | v<|>; | 54 | v<|>; |
55 | } | 55 | } |
56 | 56 | ||
57 | //- /std.rs crate:std | 57 | //- /core.rs crate:core |
58 | #[prelude_import] use future::*; | 58 | #[prelude_import] use future::*; |
59 | mod future { | 59 | mod future { |
60 | #[lang = "future_trait"] | 60 | #[lang = "future_trait"] |
@@ -72,7 +72,7 @@ mod future { | |||
72 | fn infer_desugar_async() { | 72 | fn infer_desugar_async() { |
73 | let (db, pos) = TestDB::with_position( | 73 | let (db, pos) = TestDB::with_position( |
74 | r#" | 74 | r#" |
75 | //- /main.rs crate:main deps:std | 75 | //- /main.rs crate:main deps:core |
76 | 76 | ||
77 | async fn foo() -> u64 { | 77 | async fn foo() -> u64 { |
78 | 128 | 78 | 128 |
@@ -83,7 +83,7 @@ fn test() { | |||
83 | r<|>; | 83 | r<|>; |
84 | } | 84 | } |
85 | 85 | ||
86 | //- /std.rs crate:std | 86 | //- /core.rs crate:core |
87 | #[prelude_import] use future::*; | 87 | #[prelude_import] use future::*; |
88 | mod future { | 88 | mod future { |
89 | trait Future { | 89 | trait Future { |
@@ -100,7 +100,7 @@ mod future { | |||
100 | fn infer_try() { | 100 | fn infer_try() { |
101 | let (db, pos) = TestDB::with_position( | 101 | let (db, pos) = TestDB::with_position( |
102 | r#" | 102 | r#" |
103 | //- /main.rs crate:main deps:std | 103 | //- /main.rs crate:main deps:core |
104 | 104 | ||
105 | fn test() { | 105 | fn test() { |
106 | let r: Result<i32, u64> = Result::Ok(1); | 106 | let r: Result<i32, u64> = Result::Ok(1); |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | v<|>; | 108 | v<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | 112 | ||
113 | #[prelude_import] use ops::*; | 113 | #[prelude_import] use ops::*; |
114 | mod ops { | 114 | mod ops { |
@@ -140,9 +140,9 @@ mod result { | |||
140 | fn infer_for_loop() { | 140 | fn infer_for_loop() { |
141 | let (db, pos) = TestDB::with_position( | 141 | let (db, pos) = TestDB::with_position( |
142 | r#" | 142 | r#" |
143 | //- /main.rs crate:main deps:std | 143 | //- /main.rs crate:main deps:core,alloc |
144 | 144 | ||
145 | use std::collections::Vec; | 145 | use alloc::collections::Vec; |
146 | 146 | ||
147 | fn test() { | 147 | fn test() { |
148 | let v = Vec::new(); | 148 | let v = Vec::new(); |
@@ -152,7 +152,7 @@ fn test() { | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | //- /std.rs crate:std | 155 | //- /core.rs crate:core |
156 | 156 | ||
157 | #[prelude_import] use iter::*; | 157 | #[prelude_import] use iter::*; |
158 | mod iter { | 158 | mod iter { |
@@ -161,6 +161,8 @@ mod iter { | |||
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | //- /alloc.rs crate:alloc deps:core | ||
165 | |||
164 | mod collections { | 166 | mod collections { |
165 | struct Vec<T> {} | 167 | struct Vec<T> {} |
166 | impl<T> Vec<T> { | 168 | impl<T> Vec<T> { |
@@ -168,7 +170,7 @@ mod collections { | |||
168 | fn push(&mut self, t: T) { } | 170 | fn push(&mut self, t: T) { } |
169 | } | 171 | } |
170 | 172 | ||
171 | impl<T> crate::iter::IntoIterator for Vec<T> { | 173 | impl<T> IntoIterator for Vec<T> { |
172 | type Item=T; | 174 | type Item=T; |
173 | } | 175 | } |
174 | } | 176 | } |
@@ -1110,7 +1112,6 @@ fn test() { | |||
1110 | } | 1112 | } |
1111 | 1113 | ||
1112 | #[test] | 1114 | #[test] |
1113 | #[ignore] | ||
1114 | fn impl_trait() { | 1115 | fn impl_trait() { |
1115 | assert_snapshot!( | 1116 | assert_snapshot!( |
1116 | infer(r#" | 1117 | infer(r#" |
@@ -1161,6 +1162,95 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { | |||
1161 | } | 1162 | } |
1162 | 1163 | ||
1163 | #[test] | 1164 | #[test] |
1165 | fn simple_return_pos_impl_trait() { | ||
1166 | mark::check!(lower_rpit); | ||
1167 | assert_snapshot!( | ||
1168 | infer(r#" | ||
1169 | trait Trait<T> { | ||
1170 | fn foo(&self) -> T; | ||
1171 | } | ||
1172 | fn bar() -> impl Trait<u64> { loop {} } | ||
1173 | |||
1174 | fn test() { | ||
1175 | let a = bar(); | ||
1176 | a.foo(); | ||
1177 | } | ||
1178 | "#), | ||
1179 | @r###" | ||
1180 | 30..34 'self': &Self | ||
1181 | 72..83 '{ loop {} }': ! | ||
1182 | 74..81 'loop {}': ! | ||
1183 | 79..81 '{}': () | ||
1184 | 95..130 '{ ...o(); }': () | ||
1185 | 105..106 'a': impl Trait<u64> | ||
1186 | 109..112 'bar': fn bar() -> impl Trait<u64> | ||
1187 | 109..114 'bar()': impl Trait<u64> | ||
1188 | 120..121 'a': impl Trait<u64> | ||
1189 | 120..127 'a.foo()': u64 | ||
1190 | "### | ||
1191 | ); | ||
1192 | } | ||
1193 | |||
1194 | #[test] | ||
1195 | fn more_return_pos_impl_trait() { | ||
1196 | assert_snapshot!( | ||
1197 | infer(r#" | ||
1198 | trait Iterator { | ||
1199 | type Item; | ||
1200 | fn next(&mut self) -> Self::Item; | ||
1201 | } | ||
1202 | trait Trait<T> { | ||
1203 | fn foo(&self) -> T; | ||
1204 | } | ||
1205 | fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} } | ||
1206 | fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} } | ||
1207 | |||
1208 | fn test() { | ||
1209 | let (a, b) = bar(); | ||
1210 | a.next().foo(); | ||
1211 | b.foo(); | ||
1212 | let (c, d) = baz(1u128); | ||
1213 | c.next().foo(); | ||
1214 | d.foo(); | ||
1215 | } | ||
1216 | "#), | ||
1217 | @r###" | ||
1218 | 50..54 'self': &mut Self | ||
1219 | 102..106 'self': &Self | ||
1220 | 185..196 '{ loop {} }': ({unknown}, {unknown}) | ||
1221 | 187..194 'loop {}': ! | ||
1222 | 192..194 '{}': () | ||
1223 | 207..208 't': T | ||
1224 | 269..280 '{ loop {} }': ({unknown}, {unknown}) | ||
1225 | 271..278 'loop {}': ! | ||
1226 | 276..278 '{}': () | ||
1227 | 292..414 '{ ...o(); }': () | ||
1228 | 302..308 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1229 | 303..304 'a': impl Iterator<Item = impl Trait<u32>> | ||
1230 | 306..307 'b': impl Trait<u64> | ||
1231 | 311..314 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1232 | 311..316 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) | ||
1233 | 322..323 'a': impl Iterator<Item = impl Trait<u32>> | ||
1234 | 322..330 'a.next()': impl Trait<u32> | ||
1235 | 322..336 'a.next().foo()': u32 | ||
1236 | 342..343 'b': impl Trait<u64> | ||
1237 | 342..349 'b.foo()': u64 | ||
1238 | 359..365 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1239 | 360..361 'c': impl Iterator<Item = impl Trait<u128>> | ||
1240 | 363..364 'd': impl Trait<u128> | ||
1241 | 368..371 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1242 | 368..378 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) | ||
1243 | 372..377 '1u128': u128 | ||
1244 | 384..385 'c': impl Iterator<Item = impl Trait<u128>> | ||
1245 | 384..392 'c.next()': impl Trait<u128> | ||
1246 | 384..398 'c.next().foo()': u128 | ||
1247 | 404..405 'd': impl Trait<u128> | ||
1248 | 404..411 'd.foo()': u128 | ||
1249 | "### | ||
1250 | ); | ||
1251 | } | ||
1252 | |||
1253 | #[test] | ||
1164 | fn dyn_trait() { | 1254 | fn dyn_trait() { |
1165 | assert_snapshot!( | 1255 | assert_snapshot!( |
1166 | infer(r#" | 1256 | infer(r#" |
@@ -1718,33 +1808,33 @@ fn test() { | |||
1718 | } | 1808 | } |
1719 | "#), | 1809 | "#), |
1720 | @r###" | 1810 | @r###" |
1721 | 65..69 'self': &Self | 1811 | 65..69 'self': &Self |
1722 | 166..170 'self': Self | 1812 | 166..170 'self': Self |
1723 | 172..176 'args': Args | 1813 | 172..176 'args': Args |
1724 | 240..244 'self': &Foo | 1814 | 240..244 'self': &Foo |
1725 | 255..257 '{}': () | 1815 | 255..257 '{}': () |
1726 | 335..336 'f': F | 1816 | 335..336 'f': F |
1727 | 355..357 '{}': () | 1817 | 355..357 '{}': () |
1728 | 444..690 '{ ...o(); }': () | 1818 | 444..690 '{ ...o(); }': () |
1729 | 454..459 'lazy1': Lazy<Foo, fn() -> T> | 1819 | 454..459 'lazy1': Lazy<Foo, || -> Foo> |
1730 | 476..485 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T> | 1820 | 476..485 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> |
1731 | 476..493 'Lazy::...| Foo)': Lazy<Foo, fn() -> T> | 1821 | 476..493 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> |
1732 | 486..492 '|| Foo': || -> T | 1822 | 486..492 '|| Foo': || -> Foo |
1733 | 489..492 'Foo': Foo | 1823 | 489..492 'Foo': Foo |
1734 | 503..505 'r1': {unknown} | 1824 | 503..505 'r1': usize |
1735 | 508..513 'lazy1': Lazy<Foo, fn() -> T> | 1825 | 508..513 'lazy1': Lazy<Foo, || -> Foo> |
1736 | 508..519 'lazy1.foo()': {unknown} | 1826 | 508..519 'lazy1.foo()': usize |
1737 | 561..576 'make_foo_fn_ptr': fn() -> Foo | 1827 | 561..576 'make_foo_fn_ptr': fn() -> Foo |
1738 | 592..603 'make_foo_fn': fn make_foo_fn() -> Foo | 1828 | 592..603 'make_foo_fn': fn make_foo_fn() -> Foo |
1739 | 613..618 'lazy2': Lazy<Foo, fn() -> T> | 1829 | 613..618 'lazy2': Lazy<Foo, fn() -> Foo> |
1740 | 635..644 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T> | 1830 | 635..644 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> |
1741 | 635..661 'Lazy::...n_ptr)': Lazy<Foo, fn() -> T> | 1831 | 635..661 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> |
1742 | 645..660 'make_foo_fn_ptr': fn() -> Foo | 1832 | 645..660 'make_foo_fn_ptr': fn() -> Foo |
1743 | 671..673 'r2': {unknown} | 1833 | 671..673 'r2': {unknown} |
1744 | 676..681 'lazy2': Lazy<Foo, fn() -> T> | 1834 | 676..681 'lazy2': Lazy<Foo, fn() -> Foo> |
1745 | 676..687 'lazy2.foo()': {unknown} | 1835 | 676..687 'lazy2.foo()': {unknown} |
1746 | 550..552 '{}': () | 1836 | 550..552 '{}': () |
1747 | "### | 1837 | "### |
1748 | ); | 1838 | ); |
1749 | } | 1839 | } |
1750 | 1840 | ||
@@ -2758,12 +2848,12 @@ fn test() { | |||
2758 | fn integer_range_iterate() { | 2848 | fn integer_range_iterate() { |
2759 | let t = type_at( | 2849 | let t = type_at( |
2760 | r#" | 2850 | r#" |
2761 | //- /main.rs crate:main deps:std | 2851 | //- /main.rs crate:main deps:core |
2762 | fn test() { | 2852 | fn test() { |
2763 | for x in 0..100 { x<|>; } | 2853 | for x in 0..100 { x<|>; } |
2764 | } | 2854 | } |
2765 | 2855 | ||
2766 | //- /std.rs crate:std | 2856 | //- /core.rs crate:core |
2767 | pub mod ops { | 2857 | pub mod ops { |
2768 | pub struct Range<Idx> { | 2858 | pub struct Range<Idx> { |
2769 | pub start: Idx, | 2859 | pub start: Idx, |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 61de3cc30..a72a82f5a 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -4,7 +4,7 @@ use std::sync::Arc; | |||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; | 6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; |
7 | use chalk_solve::rust_ir::{self, WellKnownTrait}; | 7 | use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; |
8 | 8 | ||
9 | use hir_def::{ | 9 | use hir_def::{ |
10 | lang_item::{lang_attr, LangItemTarget}, | 10 | lang_item::{lang_attr, LangItemTarget}, |
@@ -100,6 +100,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
100 | fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> { | 100 | fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> { |
101 | self.db.associated_ty_value(self.krate, id) | 101 | self.db.associated_ty_value(self.krate, id) |
102 | } | 102 | } |
103 | |||
103 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> { | 104 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<Interner>> { |
104 | vec![] | 105 | vec![] |
105 | } | 106 | } |
@@ -130,11 +131,34 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
130 | self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) | 131 | self.db.program_clauses_for_chalk_env(self.krate, environment.clone()) |
131 | } | 132 | } |
132 | 133 | ||
133 | fn opaque_ty_data( | 134 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { |
134 | &self, | 135 | let interned_id = crate::db::InternedOpaqueTyId::from(id); |
135 | _id: chalk_ir::OpaqueTyId<Interner>, | 136 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); |
136 | ) -> Arc<rust_ir::OpaqueTyDatum<Interner>> { | 137 | let (func, idx) = match full_id { |
137 | unimplemented!() | 138 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), |
139 | }; | ||
140 | let datas = | ||
141 | self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); | ||
142 | let data = &datas.value.impl_traits[idx as usize]; | ||
143 | let bound = OpaqueTyDatumBound { | ||
144 | bounds: make_binders( | ||
145 | data.bounds | ||
146 | .value | ||
147 | .iter() | ||
148 | .cloned() | ||
149 | .filter(|b| !b.is_error()) | ||
150 | .map(|b| b.to_chalk(self.db)) | ||
151 | .collect(), | ||
152 | 1, | ||
153 | ), | ||
154 | }; | ||
155 | let num_vars = datas.num_binders; | ||
156 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) | ||
157 | } | ||
158 | |||
159 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | ||
160 | // FIXME: actually provide the hidden type; it is relevant for auto traits | ||
161 | Ty::Unknown.to_chalk(self.db) | ||
138 | } | 162 | } |
139 | 163 | ||
140 | fn force_impl_for( | 164 | fn force_impl_for( |
@@ -150,10 +174,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
150 | // FIXME: implement actual object safety | 174 | // FIXME: implement actual object safety |
151 | true | 175 | true |
152 | } | 176 | } |
153 | |||
154 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | ||
155 | Ty::Unknown.to_chalk(self.db) | ||
156 | } | ||
157 | } | 177 | } |
158 | 178 | ||
159 | pub(crate) fn program_clauses_for_chalk_env_query( | 179 | pub(crate) fn program_clauses_for_chalk_env_query( |
@@ -460,6 +480,18 @@ impl From<crate::traits::GlobalImplId> for ImplId { | |||
460 | } | 480 | } |
461 | } | 481 | } |
462 | 482 | ||
483 | impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId { | ||
484 | fn from(id: OpaqueTyId) -> Self { | ||
485 | InternKey::from_intern_id(id.0) | ||
486 | } | ||
487 | } | ||
488 | |||
489 | impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId { | ||
490 | fn from(id: crate::db::InternedOpaqueTyId) -> Self { | ||
491 | chalk_ir::OpaqueTyId(id.as_intern_id()) | ||
492 | } | ||
493 | } | ||
494 | |||
463 | impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { | 495 | impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { |
464 | fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self { | 496 | fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self { |
465 | Self::from_intern_id(id.0) | 497 | Self::from_intern_id(id.0) |
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs index e27074ba6..56aab640c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/interner.rs +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs | |||
@@ -22,6 +22,8 @@ pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interne | |||
22 | pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; | 22 | pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; |
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | 23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; |
24 | pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; | 24 | pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; |
25 | pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; | ||
26 | pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; | ||
25 | 27 | ||
26 | impl chalk_ir::interner::Interner for Interner { | 28 | impl chalk_ir::interner::Interner for Interner { |
27 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | 29 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? |
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index 5f6daf842..18e5c9c16 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs | |||
@@ -14,10 +14,10 @@ use ra_db::salsa::InternKey; | |||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | db::HirDatabase, | 16 | db::HirDatabase, |
17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, | 17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, |
18 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, | 18 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, |
19 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, | 19 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, |
20 | Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | 20 | ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use super::interner::*; | 23 | use super::interner::*; |
@@ -68,7 +68,16 @@ impl ToChalk for Ty { | |||
68 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; | 68 | let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; |
69 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) | 69 | chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) |
70 | } | 70 | } |
71 | Ty::Opaque(_) | Ty::Unknown => { | 71 | Ty::Opaque(opaque_ty) => { |
72 | let opaque_ty_id = opaque_ty.opaque_ty_id.to_chalk(db); | ||
73 | let substitution = opaque_ty.parameters.to_chalk(db); | ||
74 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { | ||
75 | opaque_ty_id, | ||
76 | substitution, | ||
77 | })) | ||
78 | .intern(&Interner) | ||
79 | } | ||
80 | Ty::Unknown => { | ||
72 | let substitution = chalk_ir::Substitution::empty(&Interner); | 81 | let substitution = chalk_ir::Substitution::empty(&Interner); |
73 | let name = TypeName::Error; | 82 | let name = TypeName::Error; |
74 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | 83 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) |
@@ -98,7 +107,11 @@ impl ToChalk for Ty { | |||
98 | let parameters = from_chalk(db, proj.substitution); | 107 | let parameters = from_chalk(db, proj.substitution); |
99 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | 108 | Ty::Projection(ProjectionTy { associated_ty, parameters }) |
100 | } | 109 | } |
101 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | 110 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { |
111 | let impl_trait_id = from_chalk(db, opaque_ty.opaque_ty_id); | ||
112 | let parameters = from_chalk(db, opaque_ty.substitution); | ||
113 | Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) | ||
114 | } | ||
102 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { | 115 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { |
103 | let parameters: Substs = from_chalk(db, substitution); | 116 | let parameters: Substs = from_chalk(db, substitution); |
104 | Ty::Apply(ApplicationTy { | 117 | Ty::Apply(ApplicationTy { |
@@ -204,6 +217,21 @@ impl ToChalk for hir_def::TraitId { | |||
204 | } | 217 | } |
205 | } | 218 | } |
206 | 219 | ||
220 | impl ToChalk for OpaqueTyId { | ||
221 | type Chalk = chalk_ir::OpaqueTyId<Interner>; | ||
222 | |||
223 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::OpaqueTyId<Interner> { | ||
224 | db.intern_impl_trait_id(self).into() | ||
225 | } | ||
226 | |||
227 | fn from_chalk( | ||
228 | db: &dyn HirDatabase, | ||
229 | opaque_ty_id: chalk_ir::OpaqueTyId<Interner>, | ||
230 | ) -> OpaqueTyId { | ||
231 | db.lookup_intern_impl_trait_id(opaque_ty_id.into()) | ||
232 | } | ||
233 | } | ||
234 | |||
207 | impl ToChalk for TypeCtor { | 235 | impl ToChalk for TypeCtor { |
208 | type Chalk = TypeName<Interner>; | 236 | type Chalk = TypeName<Interner>; |
209 | 237 | ||
@@ -214,13 +242,18 @@ impl ToChalk for TypeCtor { | |||
214 | TypeName::AssociatedType(type_id) | 242 | TypeName::AssociatedType(type_id) |
215 | } | 243 | } |
216 | 244 | ||
245 | TypeCtor::OpaqueType(impl_trait_id) => { | ||
246 | let id = impl_trait_id.to_chalk(db); | ||
247 | TypeName::OpaqueType(id) | ||
248 | } | ||
249 | |||
217 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | 250 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), |
218 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | 251 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), |
219 | TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | 252 | TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), |
220 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { | 253 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) => { |
221 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) | 254 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) |
222 | } | 255 | } |
223 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { | 256 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) => { |
224 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) | 257 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) |
225 | } | 258 | } |
226 | 259 | ||
@@ -235,9 +268,7 @@ impl ToChalk for TypeCtor { | |||
235 | } | 268 | } |
236 | TypeCtor::Never => TypeName::Never, | 269 | TypeCtor::Never => TypeName::Never, |
237 | 270 | ||
238 | TypeCtor::Int(Uncertain::Unknown) | 271 | TypeCtor::Adt(_) |
239 | | TypeCtor::Float(Uncertain::Unknown) | ||
240 | | TypeCtor::Adt(_) | ||
241 | | TypeCtor::Array | 272 | | TypeCtor::Array |
242 | | TypeCtor::FnPtr { .. } | 273 | | TypeCtor::FnPtr { .. } |
243 | | TypeCtor::Closure { .. } => { | 274 | | TypeCtor::Closure { .. } => { |
@@ -252,23 +283,25 @@ impl ToChalk for TypeCtor { | |||
252 | match type_name { | 283 | match type_name { |
253 | TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), | 284 | TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), |
254 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | 285 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), |
255 | TypeName::OpaqueType(_) => unreachable!(), | 286 | TypeName::OpaqueType(opaque_type_id) => { |
287 | TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) | ||
288 | } | ||
256 | 289 | ||
257 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, | 290 | TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, |
258 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, | 291 | TypeName::Scalar(Scalar::Char) => TypeCtor::Char, |
259 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | 292 | TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(IntTy { |
260 | signedness: Signedness::Signed, | 293 | signedness: Signedness::Signed, |
261 | bitness: bitness_from_chalk_int(int_ty), | 294 | bitness: bitness_from_chalk_int(int_ty), |
262 | })), | 295 | }), |
263 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { | 296 | TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(IntTy { |
264 | signedness: Signedness::Unsigned, | 297 | signedness: Signedness::Unsigned, |
265 | bitness: bitness_from_chalk_uint(uint_ty), | 298 | bitness: bitness_from_chalk_uint(uint_ty), |
266 | })), | 299 | }), |
267 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { | 300 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { |
268 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) | 301 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 }) |
269 | } | 302 | } |
270 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { | 303 | TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { |
271 | TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) | 304 | TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 }) |
272 | } | 305 | } |
273 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, | 306 | TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, |
274 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), | 307 | TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), |
@@ -447,6 +480,11 @@ impl ToChalk for GenericPredicate { | |||
447 | let ty = from_chalk(db, projection_eq.ty); | 480 | let ty = from_chalk(db, projection_eq.ty); |
448 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) | 481 | GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty }) |
449 | } | 482 | } |
483 | |||
484 | chalk_ir::WhereClause::LifetimeOutlives(_) => { | ||
485 | // we shouldn't get these from Chalk | ||
486 | panic!("encountered LifetimeOutlives from Chalk") | ||
487 | } | ||
450 | } | 488 | } |
451 | } | 489 | } |
452 | } | 490 | } |
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index d88828c7c..556af7098 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs | |||
@@ -69,6 +69,11 @@ impl DebugContext<'_> { | |||
69 | let name = self.0.type_alias_data(type_alias).name.clone(); | 69 | let name = self.0.type_alias_data(type_alias).name.clone(); |
70 | write!(f, "{}::{}", trait_name, name)?; | 70 | write!(f, "{}::{}", trait_name, name)?; |
71 | } | 71 | } |
72 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { | ||
73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | ||
74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; | ||
75 | } | ||
76 | }, | ||
72 | TypeCtor::Closure { def, expr } => { | 77 | TypeCtor::Closure { def, expr } => { |
73 | write!(f, "{{closure {:?} in ", expr.into_raw())?; | 78 | write!(f, "{{closure {:?} in ", expr.into_raw())?; |
74 | match def { | 79 | match def { |
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index fa37b6955..e1fcf379d 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -126,3 +126,81 @@ pub(crate) fn completions( | |||
126 | 126 | ||
127 | Some(acc) | 127 | Some(acc) |
128 | } | 128 | } |
129 | |||
130 | #[cfg(test)] | ||
131 | mod tests { | ||
132 | use crate::completion::completion_config::CompletionConfig; | ||
133 | use crate::mock_analysis::analysis_and_position; | ||
134 | |||
135 | struct DetailAndDocumentation<'a> { | ||
136 | detail: &'a str, | ||
137 | documentation: &'a str, | ||
138 | } | ||
139 | |||
140 | fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { | ||
141 | let (analysis, position) = analysis_and_position(fixture); | ||
142 | let config = CompletionConfig::default(); | ||
143 | let completions = analysis.completions(&config, position).unwrap().unwrap(); | ||
144 | for item in completions { | ||
145 | if item.detail() == Some(expected.detail) { | ||
146 | let opt = item.documentation(); | ||
147 | let doc = opt.as_ref().map(|it| it.as_str()); | ||
148 | assert_eq!(doc, Some(expected.documentation)); | ||
149 | return; | ||
150 | } | ||
151 | } | ||
152 | panic!("completion detail not found: {}", expected.detail) | ||
153 | } | ||
154 | |||
155 | #[test] | ||
156 | fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { | ||
157 | check_detail_and_documentation( | ||
158 | r#" | ||
159 | //- /lib.rs | ||
160 | macro_rules! bar { | ||
161 | () => { | ||
162 | struct Bar; | ||
163 | impl Bar { | ||
164 | #[doc = "Do the foo"] | ||
165 | fn foo(&self) {} | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | bar!(); | ||
171 | |||
172 | fn foo() { | ||
173 | let bar = Bar; | ||
174 | bar.fo<|>; | ||
175 | } | ||
176 | "#, | ||
177 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, | ||
178 | ); | ||
179 | } | ||
180 | |||
181 | #[test] | ||
182 | fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { | ||
183 | check_detail_and_documentation( | ||
184 | r#" | ||
185 | //- /lib.rs | ||
186 | macro_rules! bar { | ||
187 | () => { | ||
188 | struct Bar; | ||
189 | impl Bar { | ||
190 | /// Do the foo | ||
191 | fn foo(&self) {} | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | bar!(); | ||
197 | |||
198 | fn foo() { | ||
199 | let bar = Bar; | ||
200 | bar.fo<|>; | ||
201 | } | ||
202 | "#, | ||
203 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, | ||
204 | ); | ||
205 | } | ||
206 | } | ||
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 15dc50cf1..e1bfd72f9 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ use ra_syntax::{ | |||
21 | }; | 21 | }; |
22 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 22 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
23 | 23 | ||
24 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceChange, SourceFileEdit}; | 24 | use crate::{Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; |
25 | 25 | ||
26 | #[derive(Debug, Copy, Clone)] | 26 | #[derive(Debug, Copy, Clone)] |
27 | pub enum Severity { | 27 | pub enum Severity { |
@@ -115,7 +115,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
115 | let node = d.ast(db); | 115 | let node = d.ast(db); |
116 | let replacement = format!("Ok({})", node.syntax()); | 116 | let replacement = format!("Ok({})", node.syntax()); |
117 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 117 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
118 | let source_change = SourceChange::source_file_edit_from(file_id, edit); | 118 | let source_change = SourceFileEdit { file_id, edit }.into(); |
119 | let fix = Fix::new("Wrap with ok", source_change); | 119 | let fix = Fix::new("Wrap with ok", source_change); |
120 | res.borrow_mut().push(Diagnostic { | 120 | res.borrow_mut().push(Diagnostic { |
121 | range: sema.diagnostics_range(d).range, | 121 | range: sema.diagnostics_range(d).range, |
@@ -187,7 +187,8 @@ fn check_struct_shorthand_initialization( | |||
187 | if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { | 187 | if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { |
188 | let field_name = name_ref.syntax().text().to_string(); | 188 | let field_name = name_ref.syntax().text().to_string(); |
189 | let field_expr = expr.syntax().text().to_string(); | 189 | let field_expr = expr.syntax().text().to_string(); |
190 | if field_name == field_expr { | 190 | let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); |
191 | if field_name == field_expr && !field_name_is_tup_index { | ||
191 | let mut edit_builder = TextEditBuilder::default(); | 192 | let mut edit_builder = TextEditBuilder::default(); |
192 | edit_builder.delete(record_field.syntax().text_range()); | 193 | edit_builder.delete(record_field.syntax().text_range()); |
193 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); | 194 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); |
@@ -321,29 +322,26 @@ mod tests { | |||
321 | fn test_wrap_return_type() { | 322 | fn test_wrap_return_type() { |
322 | let before = r#" | 323 | let before = r#" |
323 | //- /main.rs | 324 | //- /main.rs |
324 | use std::{string::String, result::Result::{self, Ok, Err}}; | 325 | use core::result::Result::{self, Ok, Err}; |
325 | 326 | ||
326 | fn div(x: i32, y: i32) -> Result<i32, String> { | 327 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
327 | if y == 0 { | 328 | if y == 0 { |
328 | return Err("div by zero".into()); | 329 | return Err(()); |
329 | } | 330 | } |
330 | x / y<|> | 331 | x / y<|> |
331 | } | 332 | } |
332 | 333 | ||
333 | //- /std/lib.rs | 334 | //- /core/lib.rs |
334 | pub mod string { | ||
335 | pub struct String { } | ||
336 | } | ||
337 | pub mod result { | 335 | pub mod result { |
338 | pub enum Result<T, E> { Ok(T), Err(E) } | 336 | pub enum Result<T, E> { Ok(T), Err(E) } |
339 | } | 337 | } |
340 | "#; | 338 | "#; |
341 | let after = r#" | 339 | let after = r#" |
342 | use std::{string::String, result::Result::{self, Ok, Err}}; | 340 | use core::result::Result::{self, Ok, Err}; |
343 | 341 | ||
344 | fn div(x: i32, y: i32) -> Result<i32, String> { | 342 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
345 | if y == 0 { | 343 | if y == 0 { |
346 | return Err("div by zero".into()); | 344 | return Err(()); |
347 | } | 345 | } |
348 | Ok(x / y) | 346 | Ok(x / y) |
349 | } | 347 | } |
@@ -355,7 +353,7 @@ mod tests { | |||
355 | fn test_wrap_return_type_handles_generic_functions() { | 353 | fn test_wrap_return_type_handles_generic_functions() { |
356 | let before = r#" | 354 | let before = r#" |
357 | //- /main.rs | 355 | //- /main.rs |
358 | use std::result::Result::{self, Ok, Err}; | 356 | use core::result::Result::{self, Ok, Err}; |
359 | 357 | ||
360 | fn div<T>(x: T) -> Result<T, i32> { | 358 | fn div<T>(x: T) -> Result<T, i32> { |
361 | if x == 0 { | 359 | if x == 0 { |
@@ -364,13 +362,13 @@ mod tests { | |||
364 | <|>x | 362 | <|>x |
365 | } | 363 | } |
366 | 364 | ||
367 | //- /std/lib.rs | 365 | //- /core/lib.rs |
368 | pub mod result { | 366 | pub mod result { |
369 | pub enum Result<T, E> { Ok(T), Err(E) } | 367 | pub enum Result<T, E> { Ok(T), Err(E) } |
370 | } | 368 | } |
371 | "#; | 369 | "#; |
372 | let after = r#" | 370 | let after = r#" |
373 | use std::result::Result::{self, Ok, Err}; | 371 | use core::result::Result::{self, Ok, Err}; |
374 | 372 | ||
375 | fn div<T>(x: T) -> Result<T, i32> { | 373 | fn div<T>(x: T) -> Result<T, i32> { |
376 | if x == 0 { | 374 | if x == 0 { |
@@ -386,32 +384,29 @@ mod tests { | |||
386 | fn test_wrap_return_type_handles_type_aliases() { | 384 | fn test_wrap_return_type_handles_type_aliases() { |
387 | let before = r#" | 385 | let before = r#" |
388 | //- /main.rs | 386 | //- /main.rs |
389 | use std::{string::String, result::Result::{self, Ok, Err}}; | 387 | use core::result::Result::{self, Ok, Err}; |
390 | 388 | ||
391 | type MyResult<T> = Result<T, String>; | 389 | type MyResult<T> = Result<T, ()>; |
392 | 390 | ||
393 | fn div(x: i32, y: i32) -> MyResult<i32> { | 391 | fn div(x: i32, y: i32) -> MyResult<i32> { |
394 | if y == 0 { | 392 | if y == 0 { |
395 | return Err("div by zero".into()); | 393 | return Err(()); |
396 | } | 394 | } |
397 | x <|>/ y | 395 | x <|>/ y |
398 | } | 396 | } |
399 | 397 | ||
400 | //- /std/lib.rs | 398 | //- /core/lib.rs |
401 | pub mod string { | ||
402 | pub struct String { } | ||
403 | } | ||
404 | pub mod result { | 399 | pub mod result { |
405 | pub enum Result<T, E> { Ok(T), Err(E) } | 400 | pub enum Result<T, E> { Ok(T), Err(E) } |
406 | } | 401 | } |
407 | "#; | 402 | "#; |
408 | let after = r#" | 403 | let after = r#" |
409 | use std::{string::String, result::Result::{self, Ok, Err}}; | 404 | use core::result::Result::{self, Ok, Err}; |
410 | 405 | ||
411 | type MyResult<T> = Result<T, String>; | 406 | type MyResult<T> = Result<T, ()>; |
412 | fn div(x: i32, y: i32) -> MyResult<i32> { | 407 | fn div(x: i32, y: i32) -> MyResult<i32> { |
413 | if y == 0 { | 408 | if y == 0 { |
414 | return Err("div by zero".into()); | 409 | return Err(()); |
415 | } | 410 | } |
416 | Ok(x / y) | 411 | Ok(x / y) |
417 | } | 412 | } |
@@ -423,16 +418,13 @@ mod tests { | |||
423 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { | 418 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { |
424 | let content = r#" | 419 | let content = r#" |
425 | //- /main.rs | 420 | //- /main.rs |
426 | use std::{string::String, result::Result::{self, Ok, Err}}; | 421 | use core::result::Result::{self, Ok, Err}; |
427 | 422 | ||
428 | fn foo() -> Result<String, i32> { | 423 | fn foo() -> Result<(), i32> { |
429 | 0<|> | 424 | 0<|> |
430 | } | 425 | } |
431 | 426 | ||
432 | //- /std/lib.rs | 427 | //- /core/lib.rs |
433 | pub mod string { | ||
434 | pub struct String { } | ||
435 | } | ||
436 | pub mod result { | 428 | pub mod result { |
437 | pub enum Result<T, E> { Ok(T), Err(E) } | 429 | pub enum Result<T, E> { Ok(T), Err(E) } |
438 | } | 430 | } |
@@ -444,7 +436,7 @@ mod tests { | |||
444 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | 436 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { |
445 | let content = r#" | 437 | let content = r#" |
446 | //- /main.rs | 438 | //- /main.rs |
447 | use std::{string::String, result::Result::{self, Ok, Err}}; | 439 | use core::result::Result::{self, Ok, Err}; |
448 | 440 | ||
449 | enum SomeOtherEnum { | 441 | enum SomeOtherEnum { |
450 | Ok(i32), | 442 | Ok(i32), |
@@ -455,10 +447,7 @@ mod tests { | |||
455 | 0<|> | 447 | 0<|> |
456 | } | 448 | } |
457 | 449 | ||
458 | //- /std/lib.rs | 450 | //- /core/lib.rs |
459 | pub mod string { | ||
460 | pub struct String { } | ||
461 | } | ||
462 | pub mod result { | 451 | pub mod result { |
463 | pub enum Result<T, E> { Ok(T), Err(E) } | 452 | pub enum Result<T, E> { Ok(T), Err(E) } |
464 | } | 453 | } |
@@ -731,6 +720,18 @@ mod tests { | |||
731 | "#, | 720 | "#, |
732 | check_struct_shorthand_initialization, | 721 | check_struct_shorthand_initialization, |
733 | ); | 722 | ); |
723 | check_not_applicable( | ||
724 | r#" | ||
725 | struct A(usize); | ||
726 | |||
727 | fn main() { | ||
728 | A { | ||
729 | 0: 0 | ||
730 | } | ||
731 | } | ||
732 | "#, | ||
733 | check_struct_shorthand_initialization, | ||
734 | ); | ||
734 | 735 | ||
735 | check_apply( | 736 | check_apply( |
736 | r#" | 737 | r#" |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 9572debd8..ca8a6a650 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -10,7 +10,7 @@ use std::{ | |||
10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | 10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; |
11 | use ra_ide_db::RootDatabase; | 11 | use ra_ide_db::RootDatabase; |
12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
13 | use stdx::SepBy; | 13 | use stdx::{split1, SepBy}; |
14 | 14 | ||
15 | use crate::display::{generic_parameters, where_predicates}; | 15 | use crate::display::{generic_parameters, where_predicates}; |
16 | 16 | ||
@@ -207,7 +207,16 @@ impl From<&'_ ast::FnDef> for FunctionSignature { | |||
207 | res.push(raw_param); | 207 | res.push(raw_param); |
208 | } | 208 | } |
209 | 209 | ||
210 | res.extend(param_list.params().map(|param| param.syntax().text().to_string())); | 210 | // macro-generated functions are missing whitespace |
211 | fn fmt_param(param: ast::Param) -> String { | ||
212 | let text = param.syntax().text().to_string(); | ||
213 | match split1(&text, ':') { | ||
214 | Some((left, right)) => format!("{}: {}", left.trim(), right.trim()), | ||
215 | _ => text, | ||
216 | } | ||
217 | } | ||
218 | |||
219 | res.extend(param_list.params().map(fmt_param)); | ||
211 | res_types.extend(param_list.params().map(|param| { | 220 | res_types.extend(param_list.params().map(|param| { |
212 | let param_text = param.syntax().text().to_string(); | 221 | let param_text = param.syntax().text().to_string(); |
213 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { | 222 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { |
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 5da28edd2..c7bb1e69f 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -92,15 +92,16 @@ impl NavigationTarget { | |||
92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
93 | if let Some(src) = module.declaration_source(db) { | 93 | if let Some(src) = module.declaration_source(db) { |
94 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); | 94 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); |
95 | return NavigationTarget::from_syntax( | 95 | let mut res = NavigationTarget::from_syntax( |
96 | frange.file_id, | 96 | frange.file_id, |
97 | name, | 97 | name, |
98 | None, | 98 | None, |
99 | frange.range, | 99 | frange.range, |
100 | src.value.syntax().kind(), | 100 | src.value.syntax().kind(), |
101 | src.value.doc_comment_text(), | ||
102 | src.value.short_label(), | ||
103 | ); | 101 | ); |
102 | res.docs = src.value.doc_comment_text(); | ||
103 | res.description = src.value.short_label(); | ||
104 | return res; | ||
104 | } | 105 | } |
105 | module.to_nav(db) | 106 | module.to_nav(db) |
106 | } | 107 | } |
@@ -130,11 +131,9 @@ impl NavigationTarget { | |||
130 | } | 131 | } |
131 | 132 | ||
132 | /// Allows `NavigationTarget` to be created from a `NameOwner` | 133 | /// Allows `NavigationTarget` to be created from a `NameOwner` |
133 | fn from_named( | 134 | pub(crate) fn from_named( |
134 | db: &RootDatabase, | 135 | db: &RootDatabase, |
135 | node: InFile<&dyn ast::NameOwner>, | 136 | node: InFile<&dyn ast::NameOwner>, |
136 | docs: Option<String>, | ||
137 | description: Option<String>, | ||
138 | ) -> NavigationTarget { | 137 | ) -> NavigationTarget { |
139 | //FIXME: use `_` instead of empty string | 138 | //FIXME: use `_` instead of empty string |
140 | let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); | 139 | let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); |
@@ -148,8 +147,6 @@ impl NavigationTarget { | |||
148 | focus_range, | 147 | focus_range, |
149 | frange.range, | 148 | frange.range, |
150 | node.value.syntax().kind(), | 149 | node.value.syntax().kind(), |
151 | docs, | ||
152 | description, | ||
153 | ) | 150 | ) |
154 | } | 151 | } |
155 | 152 | ||
@@ -159,8 +156,6 @@ impl NavigationTarget { | |||
159 | focus_range: Option<TextRange>, | 156 | focus_range: Option<TextRange>, |
160 | full_range: TextRange, | 157 | full_range: TextRange, |
161 | kind: SyntaxKind, | 158 | kind: SyntaxKind, |
162 | docs: Option<String>, | ||
163 | description: Option<String>, | ||
164 | ) -> NavigationTarget { | 159 | ) -> NavigationTarget { |
165 | NavigationTarget { | 160 | NavigationTarget { |
166 | file_id, | 161 | file_id, |
@@ -169,8 +164,8 @@ impl NavigationTarget { | |||
169 | full_range, | 164 | full_range, |
170 | focus_range, | 165 | focus_range, |
171 | container_name: None, | 166 | container_name: None, |
172 | description, | 167 | description: None, |
173 | docs, | 168 | docs: None, |
174 | } | 169 | } |
175 | } | 170 | } |
176 | } | 171 | } |
@@ -238,12 +233,11 @@ where | |||
238 | { | 233 | { |
239 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 234 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
240 | let src = self.source(db); | 235 | let src = self.source(db); |
241 | NavigationTarget::from_named( | 236 | let mut res = |
242 | db, | 237 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
243 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 238 | res.docs = src.value.doc_comment_text(); |
244 | src.value.doc_comment_text(), | 239 | res.description = src.value.short_label(); |
245 | src.value.short_label(), | 240 | res |
246 | ) | ||
247 | } | 241 | } |
248 | } | 242 | } |
249 | 243 | ||
@@ -258,15 +252,7 @@ impl ToNav for hir::Module { | |||
258 | } | 252 | } |
259 | }; | 253 | }; |
260 | let frange = original_range(db, src.with_value(syntax)); | 254 | let frange = original_range(db, src.with_value(syntax)); |
261 | NavigationTarget::from_syntax( | 255 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) |
262 | frange.file_id, | ||
263 | name, | ||
264 | focus, | ||
265 | frange.range, | ||
266 | syntax.kind(), | ||
267 | None, | ||
268 | None, | ||
269 | ) | ||
270 | } | 256 | } |
271 | } | 257 | } |
272 | 258 | ||
@@ -285,8 +271,6 @@ impl ToNav for hir::ImplDef { | |||
285 | None, | 271 | None, |
286 | frange.range, | 272 | frange.range, |
287 | src.value.syntax().kind(), | 273 | src.value.syntax().kind(), |
288 | None, | ||
289 | None, | ||
290 | ) | 274 | ) |
291 | } | 275 | } |
292 | } | 276 | } |
@@ -296,12 +280,12 @@ impl ToNav for hir::Field { | |||
296 | let src = self.source(db); | 280 | let src = self.source(db); |
297 | 281 | ||
298 | match &src.value { | 282 | match &src.value { |
299 | FieldSource::Named(it) => NavigationTarget::from_named( | 283 | FieldSource::Named(it) => { |
300 | db, | 284 | let mut res = NavigationTarget::from_named(db, src.with_value(it)); |
301 | src.with_value(it), | 285 | res.docs = it.doc_comment_text(); |
302 | it.doc_comment_text(), | 286 | res.description = it.short_label(); |
303 | it.short_label(), | 287 | res |
304 | ), | 288 | } |
305 | FieldSource::Pos(it) => { | 289 | FieldSource::Pos(it) => { |
306 | let frange = original_range(db, src.with_value(it.syntax())); | 290 | let frange = original_range(db, src.with_value(it.syntax())); |
307 | NavigationTarget::from_syntax( | 291 | NavigationTarget::from_syntax( |
@@ -310,8 +294,6 @@ impl ToNav for hir::Field { | |||
310 | None, | 294 | None, |
311 | frange.range, | 295 | frange.range, |
312 | it.syntax().kind(), | 296 | it.syntax().kind(), |
313 | None, | ||
314 | None, | ||
315 | ) | 297 | ) |
316 | } | 298 | } |
317 | } | 299 | } |
@@ -322,12 +304,10 @@ impl ToNav for hir::MacroDef { | |||
322 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 304 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
323 | let src = self.source(db); | 305 | let src = self.source(db); |
324 | log::debug!("nav target {:#?}", src.value.syntax()); | 306 | log::debug!("nav target {:#?}", src.value.syntax()); |
325 | NavigationTarget::from_named( | 307 | let mut res = |
326 | db, | 308 | NavigationTarget::from_named(db, src.as_ref().map(|it| it as &dyn ast::NameOwner)); |
327 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 309 | res.docs = src.value.doc_comment_text(); |
328 | src.value.doc_comment_text(), | 310 | res |
329 | None, | ||
330 | ) | ||
331 | } | 311 | } |
332 | } | 312 | } |
333 | 313 | ||
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index a6c86e99c..0798d2c36 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use hir::Semantics; | 1 | use hir::Semantics; |
2 | use ra_ide_db::{ | 2 | use ra_ide_db::{ |
3 | defs::{classify_name, classify_name_ref}, | 3 | defs::{classify_name, classify_name_ref, NameClass}, |
4 | symbol_index, RootDatabase, | 4 | symbol_index, RootDatabase, |
5 | }; | 5 | }; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -39,7 +39,10 @@ pub(crate) fn goto_definition( | |||
39 | reference_definition(&sema, &name_ref).to_vec() | 39 | reference_definition(&sema, &name_ref).to_vec() |
40 | }, | 40 | }, |
41 | ast::Name(name) => { | 41 | ast::Name(name) => { |
42 | let def = classify_name(&sema, &name)?.definition(); | 42 | let def = match classify_name(&sema, &name)? { |
43 | NameClass::Definition(def) | NameClass::ConstReference(def) => def, | ||
44 | NameClass::FieldShorthand { local: _, field } => field, | ||
45 | }; | ||
43 | let nav = def.try_to_nav(sema.db)?; | 46 | let nav = def.try_to_nav(sema.db)?; |
44 | vec![nav] | 47 | vec![nav] |
45 | }, | 48 | }, |
@@ -886,4 +889,23 @@ mod tests { | |||
886 | "x", | 889 | "x", |
887 | ) | 890 | ) |
888 | } | 891 | } |
892 | |||
893 | #[test] | ||
894 | fn goto_def_for_enum_variant_field() { | ||
895 | check_goto( | ||
896 | " | ||
897 | //- /lib.rs | ||
898 | enum Foo { | ||
899 | Bar { x: i32 } | ||
900 | } | ||
901 | fn baz(foo: Foo) { | ||
902 | match foo { | ||
903 | Foo::Bar { x<|> } => x | ||
904 | }; | ||
905 | } | ||
906 | ", | ||
907 | "x RECORD_FIELD_DEF FileId(1) 21..27 21..22", | ||
908 | "x: i32|x", | ||
909 | ); | ||
910 | } | ||
889 | } | 911 | } |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index d96cb5596..ad78b7671 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | 2 | ||
3 | use hir::{ | 3 | use hir::{ |
4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | 4 | Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, |
5 | ModuleSource, Semantics, | 5 | ModuleDef, ModuleSource, Semantics, |
6 | }; | 6 | }; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use ra_db::SourceDatabase; | 8 | use ra_db::SourceDatabase; |
@@ -10,22 +10,55 @@ use ra_ide_db::{ | |||
10 | defs::{classify_name, classify_name_ref, Definition}, | 10 | defs::{classify_name, classify_name_ref, Definition}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; |
14 | ast::{self, DocCommentsOwner}, | ||
15 | match_ast, AstNode, | ||
16 | SyntaxKind::*, | ||
17 | SyntaxToken, TokenAtOffset, | ||
18 | }; | ||
19 | 14 | ||
20 | use crate::{ | 15 | use crate::{ |
21 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, |
22 | FilePosition, RangeInfo, | 17 | runnables::runnable, |
18 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | ||
23 | }; | 19 | }; |
20 | use test_utils::mark; | ||
21 | |||
22 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
23 | pub struct HoverConfig { | ||
24 | pub implementations: bool, | ||
25 | pub run: bool, | ||
26 | pub debug: bool, | ||
27 | } | ||
28 | |||
29 | impl Default for HoverConfig { | ||
30 | fn default() -> Self { | ||
31 | Self { implementations: true, run: true, debug: true } | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl HoverConfig { | ||
36 | pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; | ||
37 | |||
38 | pub fn any(&self) -> bool { | ||
39 | self.implementations || self.runnable() | ||
40 | } | ||
41 | |||
42 | pub fn none(&self) -> bool { | ||
43 | !self.any() | ||
44 | } | ||
45 | |||
46 | pub fn runnable(&self) -> bool { | ||
47 | self.run || self.debug | ||
48 | } | ||
49 | } | ||
50 | |||
51 | #[derive(Debug, Clone)] | ||
52 | pub enum HoverAction { | ||
53 | Runnable(Runnable), | ||
54 | Implementaion(FilePosition), | ||
55 | } | ||
24 | 56 | ||
25 | /// Contains the results when hovering over an item | 57 | /// Contains the results when hovering over an item |
26 | #[derive(Debug, Default)] | 58 | #[derive(Debug, Default)] |
27 | pub struct HoverResult { | 59 | pub struct HoverResult { |
28 | results: Vec<String>, | 60 | results: Vec<String>, |
61 | actions: Vec<HoverAction>, | ||
29 | } | 62 | } |
30 | 63 | ||
31 | impl HoverResult { | 64 | impl HoverResult { |
@@ -53,10 +86,20 @@ impl HoverResult { | |||
53 | &self.results | 86 | &self.results |
54 | } | 87 | } |
55 | 88 | ||
89 | pub fn actions(&self) -> &[HoverAction] { | ||
90 | &self.actions | ||
91 | } | ||
92 | |||
93 | pub fn push_action(&mut self, action: HoverAction) { | ||
94 | self.actions.push(action); | ||
95 | } | ||
96 | |||
56 | /// Returns the results converted into markup | 97 | /// Returns the results converted into markup |
57 | /// for displaying in a UI | 98 | /// for displaying in a UI |
99 | /// | ||
100 | /// Does not process actions! | ||
58 | pub fn to_markup(&self) -> String { | 101 | pub fn to_markup(&self) -> String { |
59 | self.results.join("\n\n---\n") | 102 | self.results.join("\n\n___\n") |
60 | } | 103 | } |
61 | } | 104 | } |
62 | 105 | ||
@@ -87,6 +130,14 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
87 | res.extend(hover_text_from_name_kind(db, name_kind)); | 130 | res.extend(hover_text_from_name_kind(db, name_kind)); |
88 | 131 | ||
89 | if !res.is_empty() { | 132 | if !res.is_empty() { |
133 | if let Some(action) = show_implementations_action(db, name_kind) { | ||
134 | res.push_action(action); | ||
135 | } | ||
136 | |||
137 | if let Some(action) = runnable_action(&sema, name_kind, position.file_id) { | ||
138 | res.push_action(action); | ||
139 | } | ||
140 | |||
90 | return Some(RangeInfo::new(range, res)); | 141 | return Some(RangeInfo::new(range, res)); |
91 | } | 142 | } |
92 | } | 143 | } |
@@ -117,6 +168,56 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
117 | Some(RangeInfo::new(range, res)) | 168 | Some(RangeInfo::new(range, res)) |
118 | } | 169 | } |
119 | 170 | ||
171 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | ||
172 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | ||
173 | HoverAction::Implementaion(FilePosition { | ||
174 | file_id: nav_target.file_id(), | ||
175 | offset: nav_target.range().start(), | ||
176 | }) | ||
177 | } | ||
178 | |||
179 | match def { | ||
180 | Definition::ModuleDef(it) => match it { | ||
181 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | ||
182 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | ||
183 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | ||
184 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | ||
185 | _ => None, | ||
186 | }, | ||
187 | _ => None, | ||
188 | } | ||
189 | } | ||
190 | |||
191 | fn runnable_action( | ||
192 | sema: &Semantics<RootDatabase>, | ||
193 | def: Definition, | ||
194 | file_id: FileId, | ||
195 | ) -> Option<HoverAction> { | ||
196 | match def { | ||
197 | Definition::ModuleDef(it) => match it { | ||
198 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | ||
199 | ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) | ||
200 | .map(|it| HoverAction::Runnable(it)), | ||
201 | _ => None, | ||
202 | }, | ||
203 | ModuleDef::Function(it) => { | ||
204 | let src = it.source(sema.db); | ||
205 | if src.file_id != file_id.into() { | ||
206 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | ||
207 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | ||
208 | |||
209 | return None; | ||
210 | } | ||
211 | |||
212 | runnable(&sema, src.value.syntax().clone(), file_id) | ||
213 | .map(|it| HoverAction::Runnable(it)) | ||
214 | } | ||
215 | _ => None, | ||
216 | }, | ||
217 | _ => None, | ||
218 | } | ||
219 | } | ||
220 | |||
120 | fn hover_text( | 221 | fn hover_text( |
121 | docs: Option<String>, | 222 | docs: Option<String>, |
122 | desc: Option<String>, | 223 | desc: Option<String>, |
@@ -169,13 +270,15 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
169 | return match def { | 270 | return match def { |
170 | Definition::Macro(it) => { | 271 | Definition::Macro(it) => { |
171 | let src = it.source(db); | 272 | let src = it.source(db); |
172 | hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path) | 273 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
274 | hover_text(docs, Some(macro_label(&src.value)), mod_path) | ||
173 | } | 275 | } |
174 | Definition::Field(it) => { | 276 | Definition::Field(it) => { |
175 | let src = it.source(db); | 277 | let src = it.source(db); |
176 | match src.value { | 278 | match src.value { |
177 | FieldSource::Named(it) => { | 279 | FieldSource::Named(it) => { |
178 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 280 | let docs = Documentation::from_ast(&it).map(Into::into); |
281 | hover_text(docs, it.short_label(), mod_path) | ||
179 | } | 282 | } |
180 | _ => None, | 283 | _ => None, |
181 | } | 284 | } |
@@ -183,7 +286,8 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
183 | Definition::ModuleDef(it) => match it { | 286 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Module(it) => match it.definition_source(db).value { | 287 | ModuleDef::Module(it) => match it.definition_source(db).value { |
185 | ModuleSource::Module(it) => { | 288 | ModuleSource::Module(it) => { |
186 | hover_text(it.doc_comment_text(), it.short_label(), mod_path) | 289 | let docs = Documentation::from_ast(&it).map(Into::into); |
290 | hover_text(docs, it.short_label(), mod_path) | ||
187 | } | 291 | } |
188 | _ => None, | 292 | _ => None, |
189 | }, | 293 | }, |
@@ -208,10 +312,11 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
208 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> | 312 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> |
209 | where | 313 | where |
210 | D: HasSource<Ast = A>, | 314 | D: HasSource<Ast = A>, |
211 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | 315 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, |
212 | { | 316 | { |
213 | let src = def.source(db); | 317 | let src = def.source(db); |
214 | hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path) | 318 | let docs = Documentation::from_ast(&src.value).map(Into::into); |
319 | hover_text(docs, src.value.short_label(), mod_path) | ||
215 | } | 320 | } |
216 | } | 321 | } |
217 | 322 | ||
@@ -229,6 +334,9 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
229 | 334 | ||
230 | #[cfg(test)] | 335 | #[cfg(test)] |
231 | mod tests { | 336 | mod tests { |
337 | use super::*; | ||
338 | use insta::assert_debug_snapshot; | ||
339 | |||
232 | use ra_db::FileLoader; | 340 | use ra_db::FileLoader; |
233 | use ra_syntax::TextRange; | 341 | use ra_syntax::TextRange; |
234 | 342 | ||
@@ -242,7 +350,15 @@ mod tests { | |||
242 | s.map(trim_markup) | 350 | s.map(trim_markup) |
243 | } | 351 | } |
244 | 352 | ||
245 | fn check_hover_result(fixture: &str, expected: &[&str]) -> String { | 353 | fn assert_impl_action(action: &HoverAction, position: u32) { |
354 | let offset = match action { | ||
355 | HoverAction::Implementaion(pos) => pos.offset, | ||
356 | it => panic!("Unexpected hover action: {:#?}", it), | ||
357 | }; | ||
358 | assert_eq!(offset, position.into()); | ||
359 | } | ||
360 | |||
361 | fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) { | ||
246 | let (analysis, position) = analysis_and_position(fixture); | 362 | let (analysis, position) = analysis_and_position(fixture); |
247 | let hover = analysis.hover(position).unwrap().unwrap(); | 363 | let hover = analysis.hover(position).unwrap().unwrap(); |
248 | let mut results = Vec::from(hover.info.results()); | 364 | let mut results = Vec::from(hover.info.results()); |
@@ -257,7 +373,7 @@ mod tests { | |||
257 | assert_eq!(hover.info.len(), expected.len()); | 373 | assert_eq!(hover.info.len(), expected.len()); |
258 | 374 | ||
259 | let content = analysis.db.file_text(position.file_id); | 375 | let content = analysis.db.file_text(position.file_id); |
260 | content[hover.range].to_string() | 376 | (content[hover.range].to_string(), hover.info.actions().to_vec()) |
261 | } | 377 | } |
262 | 378 | ||
263 | fn check_hover_no_result(fixture: &str) { | 379 | fn check_hover_no_result(fixture: &str) { |
@@ -458,7 +574,7 @@ struct Test<K, T = u8> { | |||
458 | } | 574 | } |
459 | 575 | ||
460 | fn main() { | 576 | fn main() { |
461 | let zz<|> = Test { t: 23, k: 33 }; | 577 | let zz<|> = Test { t: 23u8, k: 33 }; |
462 | }"#, | 578 | }"#, |
463 | &["Test<i32, u8>"], | 579 | &["Test<i32, u8>"], |
464 | ); | 580 | ); |
@@ -747,7 +863,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
747 | 863 | ||
748 | #[test] | 864 | #[test] |
749 | fn test_hover_through_macro() { | 865 | fn test_hover_through_macro() { |
750 | let hover_on = check_hover_result( | 866 | let (hover_on, _) = check_hover_result( |
751 | " | 867 | " |
752 | //- /lib.rs | 868 | //- /lib.rs |
753 | macro_rules! id { | 869 | macro_rules! id { |
@@ -768,7 +884,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
768 | 884 | ||
769 | #[test] | 885 | #[test] |
770 | fn test_hover_through_expr_in_macro() { | 886 | fn test_hover_through_expr_in_macro() { |
771 | let hover_on = check_hover_result( | 887 | let (hover_on, _) = check_hover_result( |
772 | " | 888 | " |
773 | //- /lib.rs | 889 | //- /lib.rs |
774 | macro_rules! id { | 890 | macro_rules! id { |
@@ -786,7 +902,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
786 | 902 | ||
787 | #[test] | 903 | #[test] |
788 | fn test_hover_through_expr_in_macro_recursive() { | 904 | fn test_hover_through_expr_in_macro_recursive() { |
789 | let hover_on = check_hover_result( | 905 | let (hover_on, _) = check_hover_result( |
790 | " | 906 | " |
791 | //- /lib.rs | 907 | //- /lib.rs |
792 | macro_rules! id_deep { | 908 | macro_rules! id_deep { |
@@ -807,7 +923,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
807 | 923 | ||
808 | #[test] | 924 | #[test] |
809 | fn test_hover_through_func_in_macro_recursive() { | 925 | fn test_hover_through_func_in_macro_recursive() { |
810 | let hover_on = check_hover_result( | 926 | let (hover_on, _) = check_hover_result( |
811 | " | 927 | " |
812 | //- /lib.rs | 928 | //- /lib.rs |
813 | macro_rules! id_deep { | 929 | macro_rules! id_deep { |
@@ -831,7 +947,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
831 | 947 | ||
832 | #[test] | 948 | #[test] |
833 | fn test_hover_through_literal_string_in_macro() { | 949 | fn test_hover_through_literal_string_in_macro() { |
834 | let hover_on = check_hover_result( | 950 | let (hover_on, _) = check_hover_result( |
835 | r#" | 951 | r#" |
836 | //- /lib.rs | 952 | //- /lib.rs |
837 | macro_rules! arr { | 953 | macro_rules! arr { |
@@ -850,7 +966,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
850 | 966 | ||
851 | #[test] | 967 | #[test] |
852 | fn test_hover_through_assert_macro() { | 968 | fn test_hover_through_assert_macro() { |
853 | let hover_on = check_hover_result( | 969 | let (hover_on, _) = check_hover_result( |
854 | r#" | 970 | r#" |
855 | //- /lib.rs | 971 | //- /lib.rs |
856 | #[rustc_builtin_macro] | 972 | #[rustc_builtin_macro] |
@@ -926,13 +1042,14 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
926 | 1042 | ||
927 | #[test] | 1043 | #[test] |
928 | fn test_hover_trait_show_qualifiers() { | 1044 | fn test_hover_trait_show_qualifiers() { |
929 | check_hover_result( | 1045 | let (_, actions) = check_hover_result( |
930 | " | 1046 | " |
931 | //- /lib.rs | 1047 | //- /lib.rs |
932 | unsafe trait foo<|>() {} | 1048 | unsafe trait foo<|>() {} |
933 | ", | 1049 | ", |
934 | &["unsafe trait foo"], | 1050 | &["unsafe trait foo"], |
935 | ); | 1051 | ); |
1052 | assert_impl_action(&actions[0], 13); | ||
936 | } | 1053 | } |
937 | 1054 | ||
938 | #[test] | 1055 | #[test] |
@@ -951,4 +1068,246 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
951 | &["mod my"], | 1068 | &["mod my"], |
952 | ); | 1069 | ); |
953 | } | 1070 | } |
1071 | |||
1072 | #[test] | ||
1073 | fn test_hover_struct_doc_comment() { | ||
1074 | check_hover_result( | ||
1075 | r#" | ||
1076 | //- /lib.rs | ||
1077 | /// bar docs | ||
1078 | struct Bar; | ||
1079 | |||
1080 | fn foo() { | ||
1081 | let bar = Ba<|>r; | ||
1082 | } | ||
1083 | "#, | ||
1084 | &["struct Bar\n```\n___\n\nbar docs"], | ||
1085 | ); | ||
1086 | } | ||
1087 | |||
1088 | #[test] | ||
1089 | fn test_hover_struct_doc_attr() { | ||
1090 | check_hover_result( | ||
1091 | r#" | ||
1092 | //- /lib.rs | ||
1093 | #[doc = "bar docs"] | ||
1094 | struct Bar; | ||
1095 | |||
1096 | fn foo() { | ||
1097 | let bar = Ba<|>r; | ||
1098 | } | ||
1099 | "#, | ||
1100 | &["struct Bar\n```\n___\n\nbar docs"], | ||
1101 | ); | ||
1102 | } | ||
1103 | |||
1104 | #[test] | ||
1105 | fn test_hover_struct_doc_attr_multiple_and_mixed() { | ||
1106 | check_hover_result( | ||
1107 | r#" | ||
1108 | //- /lib.rs | ||
1109 | /// bar docs 0 | ||
1110 | #[doc = "bar docs 1"] | ||
1111 | #[doc = "bar docs 2"] | ||
1112 | struct Bar; | ||
1113 | |||
1114 | fn foo() { | ||
1115 | let bar = Ba<|>r; | ||
1116 | } | ||
1117 | "#, | ||
1118 | &["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"], | ||
1119 | ); | ||
1120 | } | ||
1121 | |||
1122 | #[test] | ||
1123 | fn test_hover_macro_generated_struct_fn_doc_comment() { | ||
1124 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | ||
1125 | |||
1126 | check_hover_result( | ||
1127 | r#" | ||
1128 | //- /lib.rs | ||
1129 | macro_rules! bar { | ||
1130 | () => { | ||
1131 | struct Bar; | ||
1132 | impl Bar { | ||
1133 | /// Do the foo | ||
1134 | fn foo(&self) {} | ||
1135 | } | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | bar!(); | ||
1140 | |||
1141 | fn foo() { | ||
1142 | let bar = Bar; | ||
1143 | bar.fo<|>o(); | ||
1144 | } | ||
1145 | "#, | ||
1146 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"], | ||
1147 | ); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn test_hover_macro_generated_struct_fn_doc_attr() { | ||
1152 | mark::check!(hover_macro_generated_struct_fn_doc_attr); | ||
1153 | |||
1154 | check_hover_result( | ||
1155 | r#" | ||
1156 | //- /lib.rs | ||
1157 | macro_rules! bar { | ||
1158 | () => { | ||
1159 | struct Bar; | ||
1160 | impl Bar { | ||
1161 | #[doc = "Do the foo"] | ||
1162 | fn foo(&self) {} | ||
1163 | } | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | bar!(); | ||
1168 | |||
1169 | fn foo() { | ||
1170 | let bar = Bar; | ||
1171 | bar.fo<|>o(); | ||
1172 | } | ||
1173 | "#, | ||
1174 | &["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], | ||
1175 | ); | ||
1176 | } | ||
1177 | |||
1178 | #[test] | ||
1179 | fn test_hover_trait_has_impl_action() { | ||
1180 | let (_, actions) = check_hover_result( | ||
1181 | " | ||
1182 | //- /lib.rs | ||
1183 | trait foo<|>() {} | ||
1184 | ", | ||
1185 | &["trait foo"], | ||
1186 | ); | ||
1187 | assert_impl_action(&actions[0], 6); | ||
1188 | } | ||
1189 | |||
1190 | #[test] | ||
1191 | fn test_hover_struct_has_impl_action() { | ||
1192 | let (_, actions) = check_hover_result( | ||
1193 | " | ||
1194 | //- /lib.rs | ||
1195 | struct foo<|>() {} | ||
1196 | ", | ||
1197 | &["struct foo"], | ||
1198 | ); | ||
1199 | assert_impl_action(&actions[0], 7); | ||
1200 | } | ||
1201 | |||
1202 | #[test] | ||
1203 | fn test_hover_union_has_impl_action() { | ||
1204 | let (_, actions) = check_hover_result( | ||
1205 | " | ||
1206 | //- /lib.rs | ||
1207 | union foo<|>() {} | ||
1208 | ", | ||
1209 | &["union foo"], | ||
1210 | ); | ||
1211 | assert_impl_action(&actions[0], 6); | ||
1212 | } | ||
1213 | |||
1214 | #[test] | ||
1215 | fn test_hover_enum_has_impl_action() { | ||
1216 | let (_, actions) = check_hover_result( | ||
1217 | " | ||
1218 | //- /lib.rs | ||
1219 | enum foo<|>() { | ||
1220 | A, | ||
1221 | B | ||
1222 | } | ||
1223 | ", | ||
1224 | &["enum foo"], | ||
1225 | ); | ||
1226 | assert_impl_action(&actions[0], 5); | ||
1227 | } | ||
1228 | |||
1229 | #[test] | ||
1230 | fn test_hover_test_has_action() { | ||
1231 | let (_, actions) = check_hover_result( | ||
1232 | " | ||
1233 | //- /lib.rs | ||
1234 | #[test] | ||
1235 | fn foo_<|>test() {} | ||
1236 | ", | ||
1237 | &["fn foo_test()"], | ||
1238 | ); | ||
1239 | assert_debug_snapshot!(actions, | ||
1240 | @r###" | ||
1241 | [ | ||
1242 | Runnable( | ||
1243 | Runnable { | ||
1244 | nav: NavigationTarget { | ||
1245 | file_id: FileId( | ||
1246 | 1, | ||
1247 | ), | ||
1248 | full_range: 0..24, | ||
1249 | name: "foo_test", | ||
1250 | kind: FN_DEF, | ||
1251 | focus_range: Some( | ||
1252 | 11..19, | ||
1253 | ), | ||
1254 | container_name: None, | ||
1255 | description: None, | ||
1256 | docs: None, | ||
1257 | }, | ||
1258 | kind: Test { | ||
1259 | test_id: Path( | ||
1260 | "foo_test", | ||
1261 | ), | ||
1262 | attr: TestAttr { | ||
1263 | ignore: false, | ||
1264 | }, | ||
1265 | }, | ||
1266 | cfg_exprs: [], | ||
1267 | }, | ||
1268 | ), | ||
1269 | ] | ||
1270 | "###); | ||
1271 | } | ||
1272 | |||
1273 | #[test] | ||
1274 | fn test_hover_test_mod_has_action() { | ||
1275 | let (_, actions) = check_hover_result( | ||
1276 | " | ||
1277 | //- /lib.rs | ||
1278 | mod tests<|> { | ||
1279 | #[test] | ||
1280 | fn foo_test() {} | ||
1281 | } | ||
1282 | ", | ||
1283 | &["mod tests"], | ||
1284 | ); | ||
1285 | assert_debug_snapshot!(actions, | ||
1286 | @r###" | ||
1287 | [ | ||
1288 | Runnable( | ||
1289 | Runnable { | ||
1290 | nav: NavigationTarget { | ||
1291 | file_id: FileId( | ||
1292 | 1, | ||
1293 | ), | ||
1294 | full_range: 0..46, | ||
1295 | name: "tests", | ||
1296 | kind: MODULE, | ||
1297 | focus_range: Some( | ||
1298 | 4..9, | ||
1299 | ), | ||
1300 | container_name: None, | ||
1301 | description: None, | ||
1302 | docs: None, | ||
1303 | }, | ||
1304 | kind: TestMod { | ||
1305 | path: "tests", | ||
1306 | }, | ||
1307 | cfg_exprs: [], | ||
1308 | }, | ||
1309 | ), | ||
1310 | ] | ||
1311 | "###); | ||
1312 | } | ||
954 | } | 1313 | } |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 75bd3c96b..7eb2cef73 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -149,11 +149,10 @@ fn get_param_name_hints( | |||
149 | ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(), | 149 | ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(), |
150 | _ => return None, | 150 | _ => return None, |
151 | }; | 151 | }; |
152 | let args_count = args.clone().count(); | ||
153 | 152 | ||
154 | let fn_signature = get_fn_signature(sema, &expr)?; | 153 | let fn_signature = get_fn_signature(sema, &expr)?; |
155 | let n_params_to_skip = | 154 | let n_params_to_skip = |
156 | if fn_signature.has_self_param && fn_signature.parameter_names.len() > args_count { | 155 | if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { |
157 | 1 | 156 | 1 |
158 | } else { | 157 | } else { |
159 | 0 | 158 | 0 |
@@ -416,7 +415,7 @@ struct Test<K, T = u8> { | |||
416 | } | 415 | } |
417 | 416 | ||
418 | fn main() { | 417 | fn main() { |
419 | let zz = Test { t: 23, k: 33 }; | 418 | let zz = Test { t: 23u8, k: 33 }; |
420 | let zz_ref = &zz; | 419 | let zz_ref = &zz; |
421 | }"#, | 420 | }"#, |
422 | ); | 421 | ); |
@@ -429,7 +428,7 @@ fn main() { | |||
429 | label: "Test<i32>", | 428 | label: "Test<i32>", |
430 | }, | 429 | }, |
431 | InlayHint { | 430 | InlayHint { |
432 | range: 105..111, | 431 | range: 107..113, |
433 | kind: TypeHint, | 432 | kind: TypeHint, |
434 | label: "&Test<i32>", | 433 | label: "&Test<i32>", |
435 | }, | 434 | }, |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 12d5716e8..28f686767 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -66,7 +66,7 @@ pub use crate::{ | |||
66 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 66 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, |
67 | expand_macro::ExpandedMacro, | 67 | expand_macro::ExpandedMacro, |
68 | folding_ranges::{Fold, FoldKind}, | 68 | folding_ranges::{Fold, FoldKind}, |
69 | hover::HoverResult, | 69 | hover::{HoverAction, HoverConfig, HoverResult}, |
70 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 70 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
71 | references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, | 71 | references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, |
72 | runnables::{Runnable, RunnableKind, TestId}, | 72 | runnables::{Runnable, RunnableKind, TestId}, |
@@ -77,7 +77,7 @@ pub use crate::{ | |||
77 | }; | 77 | }; |
78 | 78 | ||
79 | pub use hir::Documentation; | 79 | pub use hir::Documentation; |
80 | pub use ra_assists::{AssistConfig, AssistId}; | 80 | pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist}; |
81 | pub use ra_db::{ | 81 | pub use ra_db::{ |
82 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, | 82 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, |
83 | }; | 83 | }; |
@@ -142,14 +142,6 @@ pub struct AnalysisHost { | |||
142 | db: RootDatabase, | 142 | db: RootDatabase, |
143 | } | 143 | } |
144 | 144 | ||
145 | #[derive(Debug)] | ||
146 | pub struct Assist { | ||
147 | pub id: AssistId, | ||
148 | pub label: String, | ||
149 | pub group_label: Option<String>, | ||
150 | pub source_change: SourceChange, | ||
151 | } | ||
152 | |||
153 | impl AnalysisHost { | 145 | impl AnalysisHost { |
154 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { | 146 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { |
155 | AnalysisHost { db: RootDatabase::new(lru_capacity) } | 147 | AnalysisHost { db: RootDatabase::new(lru_capacity) } |
@@ -470,20 +462,23 @@ impl Analysis { | |||
470 | self.with_db(|db| completion::completions(db, config, position).map(Into::into)) | 462 | self.with_db(|db| completion::completions(db, config, position).map(Into::into)) |
471 | } | 463 | } |
472 | 464 | ||
473 | /// Computes assists (aka code actions aka intentions) for the given | 465 | /// Computes resolved assists with source changes for the given position. |
466 | pub fn resolved_assists( | ||
467 | &self, | ||
468 | config: &AssistConfig, | ||
469 | frange: FileRange, | ||
470 | ) -> Cancelable<Vec<ResolvedAssist>> { | ||
471 | self.with_db(|db| ra_assists::Assist::resolved(db, config, frange)) | ||
472 | } | ||
473 | |||
474 | /// Computes unresolved assists (aka code actions aka intentions) for the given | ||
474 | /// position. | 475 | /// position. |
475 | pub fn assists(&self, config: &AssistConfig, frange: FileRange) -> Cancelable<Vec<Assist>> { | 476 | pub fn unresolved_assists( |
476 | self.with_db(|db| { | 477 | &self, |
477 | ra_assists::Assist::resolved(db, config, frange) | 478 | config: &AssistConfig, |
478 | .into_iter() | 479 | frange: FileRange, |
479 | .map(|assist| Assist { | 480 | ) -> Cancelable<Vec<Assist>> { |
480 | id: assist.assist.id, | 481 | self.with_db(|db| Assist::unresolved(db, config, frange)) |
481 | label: assist.assist.label, | ||
482 | group_label: assist.assist.group.map(|it| it.0), | ||
483 | source_change: assist.source_change, | ||
484 | }) | ||
485 | .collect() | ||
486 | }) | ||
487 | } | 482 | } |
488 | 483 | ||
489 | /// Computes the set of diagnostics for the given file. | 484 | /// Computes the set of diagnostics for the given file. |
@@ -508,7 +503,7 @@ impl Analysis { | |||
508 | ) -> Cancelable<Result<SourceChange, SsrError>> { | 503 | ) -> Cancelable<Result<SourceChange, SsrError>> { |
509 | self.with_db(|db| { | 504 | self.with_db(|db| { |
510 | let edits = ssr::parse_search_replace(query, parse_only, db)?; | 505 | let edits = ssr::parse_search_replace(query, parse_only, db)?; |
511 | Ok(SourceChange::source_file_edits(edits)) | 506 | Ok(SourceChange::from(edits)) |
512 | }) | 507 | }) |
513 | } | 508 | } |
514 | 509 | ||
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index 28c6349b1..915d4f4d3 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -171,7 +171,7 @@ fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo | |||
171 | ), | 171 | ), |
172 | }); | 172 | }); |
173 | 173 | ||
174 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) | 174 | Some(RangeInfo::new(range, SourceChange::from(edits))) |
175 | } | 175 | } |
176 | 176 | ||
177 | fn text_edit_from_self_param( | 177 | fn text_edit_from_self_param( |
@@ -234,7 +234,7 @@ fn rename_self_to_param( | |||
234 | let range = ast::SelfParam::cast(self_token.parent()) | 234 | let range = ast::SelfParam::cast(self_token.parent()) |
235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | 235 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); |
236 | 236 | ||
237 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edits))) | 237 | Some(RangeInfo::new(range, SourceChange::from(edits))) |
238 | } | 238 | } |
239 | 239 | ||
240 | fn rename_reference( | 240 | fn rename_reference( |
@@ -253,7 +253,7 @@ fn rename_reference( | |||
253 | return None; | 253 | return None; |
254 | } | 254 | } |
255 | 255 | ||
256 | Some(RangeInfo::new(range, SourceChange::source_file_edits(edit))) | 256 | Some(RangeInfo::new(range, SourceChange::from(edit))) |
257 | } | 257 | } |
258 | 258 | ||
259 | #[cfg(test)] | 259 | #[cfg(test)] |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index 286d45eee..fc57dc33d 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -1,31 +1,31 @@ | |||
1 | use std::fmt; | ||
2 | |||
1 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; | 3 | use hir::{AsAssocItem, Attrs, HirFileId, InFile, Semantics}; |
2 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_cfg::CfgExpr; | ||
3 | use ra_ide_db::RootDatabase; | 6 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 7 | use ra_syntax::{ |
5 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, | 8 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner, ModuleItemOwner, NameOwner}, |
6 | match_ast, SyntaxNode, TextRange, | 9 | match_ast, SyntaxNode, |
7 | }; | 10 | }; |
8 | 11 | ||
9 | use crate::FileId; | 12 | use crate::{display::ToNav, FileId, NavigationTarget}; |
10 | use ast::DocCommentsOwner; | ||
11 | use ra_cfg::CfgExpr; | ||
12 | use std::fmt::Display; | ||
13 | 13 | ||
14 | #[derive(Debug)] | 14 | #[derive(Debug, Clone)] |
15 | pub struct Runnable { | 15 | pub struct Runnable { |
16 | pub range: TextRange, | 16 | pub nav: NavigationTarget, |
17 | pub kind: RunnableKind, | 17 | pub kind: RunnableKind, |
18 | pub cfg_exprs: Vec<CfgExpr>, | 18 | pub cfg_exprs: Vec<CfgExpr>, |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug, Clone)] |
22 | pub enum TestId { | 22 | pub enum TestId { |
23 | Name(String), | 23 | Name(String), |
24 | Path(String), | 24 | Path(String), |
25 | } | 25 | } |
26 | 26 | ||
27 | impl Display for TestId { | 27 | impl fmt::Display for TestId { |
28 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 28 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
29 | match self { | 29 | match self { |
30 | TestId::Name(name) => write!(f, "{}", name), | 30 | TestId::Name(name) => write!(f, "{}", name), |
31 | TestId::Path(path) => write!(f, "{}", path), | 31 | TestId::Path(path) => write!(f, "{}", path), |
@@ -33,7 +33,7 @@ impl Display for TestId { | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | #[derive(Debug)] | 36 | #[derive(Debug, Clone)] |
37 | pub enum RunnableKind { | 37 | pub enum RunnableKind { |
38 | Test { test_id: TestId, attr: TestAttr }, | 38 | Test { test_id: TestId, attr: TestAttr }, |
39 | TestMod { path: String }, | 39 | TestMod { path: String }, |
@@ -42,6 +42,42 @@ pub enum RunnableKind { | |||
42 | Bin, | 42 | Bin, |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Debug, Eq, PartialEq)] | ||
46 | pub struct RunnableAction { | ||
47 | pub run_title: &'static str, | ||
48 | pub debugee: bool, | ||
49 | } | ||
50 | |||
51 | const TEST: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Test", debugee: true }; | ||
52 | const DOCTEST: RunnableAction = | ||
53 | RunnableAction { run_title: "▶\u{fe0e} Run Doctest", debugee: false }; | ||
54 | const BENCH: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Bench", debugee: true }; | ||
55 | const BIN: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run", debugee: true }; | ||
56 | |||
57 | impl Runnable { | ||
58 | // test package::module::testname | ||
59 | pub fn label(&self, target: Option<String>) -> String { | ||
60 | match &self.kind { | ||
61 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
62 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
63 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
64 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
65 | RunnableKind::Bin => { | ||
66 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | pub fn action(&self) -> &'static RunnableAction { | ||
72 | match &self.kind { | ||
73 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => &TEST, | ||
74 | RunnableKind::DocTest { .. } => &DOCTEST, | ||
75 | RunnableKind::Bench { .. } => &BENCH, | ||
76 | RunnableKind::Bin => &BIN, | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
45 | // Feature: Run | 81 | // Feature: Run |
46 | // | 82 | // |
47 | // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor | 83 | // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor |
@@ -59,7 +95,11 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | |||
59 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() | 95 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() |
60 | } | 96 | } |
61 | 97 | ||
62 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode, file_id: FileId) -> Option<Runnable> { | 98 | pub(crate) fn runnable( |
99 | sema: &Semantics<RootDatabase>, | ||
100 | item: SyntaxNode, | ||
101 | file_id: FileId, | ||
102 | ) -> Option<Runnable> { | ||
63 | match_ast! { | 103 | match_ast! { |
64 | match item { | 104 | match item { |
65 | ast::FnDef(it) => runnable_fn(sema, it, file_id), | 105 | ast::FnDef(it) => runnable_fn(sema, it, file_id), |
@@ -131,10 +171,11 @@ fn runnable_fn( | |||
131 | let cfg_exprs = | 171 | let cfg_exprs = |
132 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | 172 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); |
133 | 173 | ||
134 | Some(Runnable { range: fn_def.syntax().text_range(), kind, cfg_exprs }) | 174 | let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); |
175 | Some(Runnable { nav, kind, cfg_exprs }) | ||
135 | } | 176 | } |
136 | 177 | ||
137 | #[derive(Debug)] | 178 | #[derive(Debug, Copy, Clone)] |
138 | pub struct TestAttr { | 179 | pub struct TestAttr { |
139 | pub ignore: bool, | 180 | pub ignore: bool, |
140 | } | 181 | } |
@@ -183,7 +224,6 @@ fn runnable_mod( | |||
183 | if !has_test_function { | 224 | if !has_test_function { |
184 | return None; | 225 | return None; |
185 | } | 226 | } |
186 | let range = module.syntax().text_range(); | ||
187 | let module_def = sema.to_def(&module)?; | 227 | let module_def = sema.to_def(&module)?; |
188 | 228 | ||
189 | let path = module_def | 229 | let path = module_def |
@@ -197,7 +237,8 @@ fn runnable_mod( | |||
197 | let cfg_exprs = | 237 | let cfg_exprs = |
198 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); | 238 | attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); |
199 | 239 | ||
200 | Some(Runnable { range, kind: RunnableKind::TestMod { path }, cfg_exprs }) | 240 | let nav = module_def.to_nav(sema.db); |
241 | Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) | ||
201 | } | 242 | } |
202 | 243 | ||
203 | #[cfg(test)] | 244 | #[cfg(test)] |
@@ -206,6 +247,15 @@ mod tests { | |||
206 | 247 | ||
207 | use crate::mock_analysis::analysis_and_position; | 248 | use crate::mock_analysis::analysis_and_position; |
208 | 249 | ||
250 | use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; | ||
251 | |||
252 | fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { | ||
253 | assert_eq!( | ||
254 | actions, | ||
255 | runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() | ||
256 | ); | ||
257 | } | ||
258 | |||
209 | #[test] | 259 | #[test] |
210 | fn test_runnables() { | 260 | fn test_runnables() { |
211 | let (analysis, pos) = analysis_and_position( | 261 | let (analysis, pos) = analysis_and_position( |
@@ -220,6 +270,9 @@ mod tests { | |||
220 | #[test] | 270 | #[test] |
221 | #[ignore] | 271 | #[ignore] |
222 | fn test_foo() {} | 272 | fn test_foo() {} |
273 | |||
274 | #[bench] | ||
275 | fn bench() {} | ||
223 | "#, | 276 | "#, |
224 | ); | 277 | ); |
225 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 278 | let runnables = analysis.runnables(pos.file_id).unwrap(); |
@@ -227,12 +280,38 @@ mod tests { | |||
227 | @r###" | 280 | @r###" |
228 | [ | 281 | [ |
229 | Runnable { | 282 | Runnable { |
230 | range: 1..21, | 283 | nav: NavigationTarget { |
284 | file_id: FileId( | ||
285 | 1, | ||
286 | ), | ||
287 | full_range: 1..21, | ||
288 | name: "main", | ||
289 | kind: FN_DEF, | ||
290 | focus_range: Some( | ||
291 | 12..16, | ||
292 | ), | ||
293 | container_name: None, | ||
294 | description: None, | ||
295 | docs: None, | ||
296 | }, | ||
231 | kind: Bin, | 297 | kind: Bin, |
232 | cfg_exprs: [], | 298 | cfg_exprs: [], |
233 | }, | 299 | }, |
234 | Runnable { | 300 | Runnable { |
235 | range: 22..46, | 301 | nav: NavigationTarget { |
302 | file_id: FileId( | ||
303 | 1, | ||
304 | ), | ||
305 | full_range: 22..46, | ||
306 | name: "test_foo", | ||
307 | kind: FN_DEF, | ||
308 | focus_range: Some( | ||
309 | 33..41, | ||
310 | ), | ||
311 | container_name: None, | ||
312 | description: None, | ||
313 | docs: None, | ||
314 | }, | ||
236 | kind: Test { | 315 | kind: Test { |
237 | test_id: Path( | 316 | test_id: Path( |
238 | "test_foo", | 317 | "test_foo", |
@@ -244,7 +323,20 @@ mod tests { | |||
244 | cfg_exprs: [], | 323 | cfg_exprs: [], |
245 | }, | 324 | }, |
246 | Runnable { | 325 | Runnable { |
247 | range: 47..81, | 326 | nav: NavigationTarget { |
327 | file_id: FileId( | ||
328 | 1, | ||
329 | ), | ||
330 | full_range: 47..81, | ||
331 | name: "test_foo", | ||
332 | kind: FN_DEF, | ||
333 | focus_range: Some( | ||
334 | 68..76, | ||
335 | ), | ||
336 | container_name: None, | ||
337 | description: None, | ||
338 | docs: None, | ||
339 | }, | ||
248 | kind: Test { | 340 | kind: Test { |
249 | test_id: Path( | 341 | test_id: Path( |
250 | "test_foo", | 342 | "test_foo", |
@@ -255,9 +347,32 @@ mod tests { | |||
255 | }, | 347 | }, |
256 | cfg_exprs: [], | 348 | cfg_exprs: [], |
257 | }, | 349 | }, |
350 | Runnable { | ||
351 | nav: NavigationTarget { | ||
352 | file_id: FileId( | ||
353 | 1, | ||
354 | ), | ||
355 | full_range: 82..104, | ||
356 | name: "bench", | ||
357 | kind: FN_DEF, | ||
358 | focus_range: Some( | ||
359 | 94..99, | ||
360 | ), | ||
361 | container_name: None, | ||
362 | description: None, | ||
363 | docs: None, | ||
364 | }, | ||
365 | kind: Bench { | ||
366 | test_id: Path( | ||
367 | "bench", | ||
368 | ), | ||
369 | }, | ||
370 | cfg_exprs: [], | ||
371 | }, | ||
258 | ] | 372 | ] |
259 | "### | 373 | "### |
260 | ); | 374 | ); |
375 | assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]); | ||
261 | } | 376 | } |
262 | 377 | ||
263 | #[test] | 378 | #[test] |
@@ -279,12 +394,38 @@ mod tests { | |||
279 | @r###" | 394 | @r###" |
280 | [ | 395 | [ |
281 | Runnable { | 396 | Runnable { |
282 | range: 1..21, | 397 | nav: NavigationTarget { |
398 | file_id: FileId( | ||
399 | 1, | ||
400 | ), | ||
401 | full_range: 1..21, | ||
402 | name: "main", | ||
403 | kind: FN_DEF, | ||
404 | focus_range: Some( | ||
405 | 12..16, | ||
406 | ), | ||
407 | container_name: None, | ||
408 | description: None, | ||
409 | docs: None, | ||
410 | }, | ||
283 | kind: Bin, | 411 | kind: Bin, |
284 | cfg_exprs: [], | 412 | cfg_exprs: [], |
285 | }, | 413 | }, |
286 | Runnable { | 414 | Runnable { |
287 | range: 22..64, | 415 | nav: NavigationTarget { |
416 | file_id: FileId( | ||
417 | 1, | ||
418 | ), | ||
419 | full_range: 22..64, | ||
420 | name: "foo", | ||
421 | kind: FN_DEF, | ||
422 | focus_range: Some( | ||
423 | 56..59, | ||
424 | ), | ||
425 | container_name: None, | ||
426 | description: None, | ||
427 | docs: None, | ||
428 | }, | ||
288 | kind: DocTest { | 429 | kind: DocTest { |
289 | test_id: Path( | 430 | test_id: Path( |
290 | "foo", | 431 | "foo", |
@@ -295,6 +436,7 @@ mod tests { | |||
295 | ] | 436 | ] |
296 | "### | 437 | "### |
297 | ); | 438 | ); |
439 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
298 | } | 440 | } |
299 | 441 | ||
300 | #[test] | 442 | #[test] |
@@ -319,12 +461,38 @@ mod tests { | |||
319 | @r###" | 461 | @r###" |
320 | [ | 462 | [ |
321 | Runnable { | 463 | Runnable { |
322 | range: 1..21, | 464 | nav: NavigationTarget { |
465 | file_id: FileId( | ||
466 | 1, | ||
467 | ), | ||
468 | full_range: 1..21, | ||
469 | name: "main", | ||
470 | kind: FN_DEF, | ||
471 | focus_range: Some( | ||
472 | 12..16, | ||
473 | ), | ||
474 | container_name: None, | ||
475 | description: None, | ||
476 | docs: None, | ||
477 | }, | ||
323 | kind: Bin, | 478 | kind: Bin, |
324 | cfg_exprs: [], | 479 | cfg_exprs: [], |
325 | }, | 480 | }, |
326 | Runnable { | 481 | Runnable { |
327 | range: 51..105, | 482 | nav: NavigationTarget { |
483 | file_id: FileId( | ||
484 | 1, | ||
485 | ), | ||
486 | full_range: 51..105, | ||
487 | name: "foo", | ||
488 | kind: FN_DEF, | ||
489 | focus_range: Some( | ||
490 | 97..100, | ||
491 | ), | ||
492 | container_name: None, | ||
493 | description: None, | ||
494 | docs: None, | ||
495 | }, | ||
328 | kind: DocTest { | 496 | kind: DocTest { |
329 | test_id: Path( | 497 | test_id: Path( |
330 | "Data::foo", | 498 | "Data::foo", |
@@ -335,6 +503,7 @@ mod tests { | |||
335 | ] | 503 | ] |
336 | "### | 504 | "### |
337 | ); | 505 | ); |
506 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
338 | } | 507 | } |
339 | 508 | ||
340 | #[test] | 509 | #[test] |
@@ -354,14 +523,40 @@ mod tests { | |||
354 | @r###" | 523 | @r###" |
355 | [ | 524 | [ |
356 | Runnable { | 525 | Runnable { |
357 | range: 1..59, | 526 | nav: NavigationTarget { |
527 | file_id: FileId( | ||
528 | 1, | ||
529 | ), | ||
530 | full_range: 1..59, | ||
531 | name: "test_mod", | ||
532 | kind: MODULE, | ||
533 | focus_range: Some( | ||
534 | 13..21, | ||
535 | ), | ||
536 | container_name: None, | ||
537 | description: None, | ||
538 | docs: None, | ||
539 | }, | ||
358 | kind: TestMod { | 540 | kind: TestMod { |
359 | path: "test_mod", | 541 | path: "test_mod", |
360 | }, | 542 | }, |
361 | cfg_exprs: [], | 543 | cfg_exprs: [], |
362 | }, | 544 | }, |
363 | Runnable { | 545 | Runnable { |
364 | range: 28..57, | 546 | nav: NavigationTarget { |
547 | file_id: FileId( | ||
548 | 1, | ||
549 | ), | ||
550 | full_range: 28..57, | ||
551 | name: "test_foo1", | ||
552 | kind: FN_DEF, | ||
553 | focus_range: Some( | ||
554 | 43..52, | ||
555 | ), | ||
556 | container_name: None, | ||
557 | description: None, | ||
558 | docs: None, | ||
559 | }, | ||
365 | kind: Test { | 560 | kind: Test { |
366 | test_id: Path( | 561 | test_id: Path( |
367 | "test_mod::test_foo1", | 562 | "test_mod::test_foo1", |
@@ -375,6 +570,7 @@ mod tests { | |||
375 | ] | 570 | ] |
376 | "### | 571 | "### |
377 | ); | 572 | ); |
573 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
378 | } | 574 | } |
379 | 575 | ||
380 | #[test] | 576 | #[test] |
@@ -396,14 +592,40 @@ mod tests { | |||
396 | @r###" | 592 | @r###" |
397 | [ | 593 | [ |
398 | Runnable { | 594 | Runnable { |
399 | range: 23..85, | 595 | nav: NavigationTarget { |
596 | file_id: FileId( | ||
597 | 1, | ||
598 | ), | ||
599 | full_range: 23..85, | ||
600 | name: "test_mod", | ||
601 | kind: MODULE, | ||
602 | focus_range: Some( | ||
603 | 27..35, | ||
604 | ), | ||
605 | container_name: None, | ||
606 | description: None, | ||
607 | docs: None, | ||
608 | }, | ||
400 | kind: TestMod { | 609 | kind: TestMod { |
401 | path: "foo::test_mod", | 610 | path: "foo::test_mod", |
402 | }, | 611 | }, |
403 | cfg_exprs: [], | 612 | cfg_exprs: [], |
404 | }, | 613 | }, |
405 | Runnable { | 614 | Runnable { |
406 | range: 46..79, | 615 | nav: NavigationTarget { |
616 | file_id: FileId( | ||
617 | 1, | ||
618 | ), | ||
619 | full_range: 46..79, | ||
620 | name: "test_foo1", | ||
621 | kind: FN_DEF, | ||
622 | focus_range: Some( | ||
623 | 65..74, | ||
624 | ), | ||
625 | container_name: None, | ||
626 | description: None, | ||
627 | docs: None, | ||
628 | }, | ||
407 | kind: Test { | 629 | kind: Test { |
408 | test_id: Path( | 630 | test_id: Path( |
409 | "foo::test_mod::test_foo1", | 631 | "foo::test_mod::test_foo1", |
@@ -417,6 +639,7 @@ mod tests { | |||
417 | ] | 639 | ] |
418 | "### | 640 | "### |
419 | ); | 641 | ); |
642 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
420 | } | 643 | } |
421 | 644 | ||
422 | #[test] | 645 | #[test] |
@@ -440,14 +663,40 @@ mod tests { | |||
440 | @r###" | 663 | @r###" |
441 | [ | 664 | [ |
442 | Runnable { | 665 | Runnable { |
443 | range: 41..115, | 666 | nav: NavigationTarget { |
667 | file_id: FileId( | ||
668 | 1, | ||
669 | ), | ||
670 | full_range: 41..115, | ||
671 | name: "test_mod", | ||
672 | kind: MODULE, | ||
673 | focus_range: Some( | ||
674 | 45..53, | ||
675 | ), | ||
676 | container_name: None, | ||
677 | description: None, | ||
678 | docs: None, | ||
679 | }, | ||
444 | kind: TestMod { | 680 | kind: TestMod { |
445 | path: "foo::bar::test_mod", | 681 | path: "foo::bar::test_mod", |
446 | }, | 682 | }, |
447 | cfg_exprs: [], | 683 | cfg_exprs: [], |
448 | }, | 684 | }, |
449 | Runnable { | 685 | Runnable { |
450 | range: 68..105, | 686 | nav: NavigationTarget { |
687 | file_id: FileId( | ||
688 | 1, | ||
689 | ), | ||
690 | full_range: 68..105, | ||
691 | name: "test_foo1", | ||
692 | kind: FN_DEF, | ||
693 | focus_range: Some( | ||
694 | 91..100, | ||
695 | ), | ||
696 | container_name: None, | ||
697 | description: None, | ||
698 | docs: None, | ||
699 | }, | ||
451 | kind: Test { | 700 | kind: Test { |
452 | test_id: Path( | 701 | test_id: Path( |
453 | "foo::bar::test_mod::test_foo1", | 702 | "foo::bar::test_mod::test_foo1", |
@@ -461,6 +710,7 @@ mod tests { | |||
461 | ] | 710 | ] |
462 | "### | 711 | "### |
463 | ); | 712 | ); |
713 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
464 | } | 714 | } |
465 | 715 | ||
466 | #[test] | 716 | #[test] |
@@ -479,7 +729,20 @@ mod tests { | |||
479 | @r###" | 729 | @r###" |
480 | [ | 730 | [ |
481 | Runnable { | 731 | Runnable { |
482 | range: 1..58, | 732 | nav: NavigationTarget { |
733 | file_id: FileId( | ||
734 | 1, | ||
735 | ), | ||
736 | full_range: 1..58, | ||
737 | name: "test_foo1", | ||
738 | kind: FN_DEF, | ||
739 | focus_range: Some( | ||
740 | 44..53, | ||
741 | ), | ||
742 | container_name: None, | ||
743 | description: None, | ||
744 | docs: None, | ||
745 | }, | ||
483 | kind: Test { | 746 | kind: Test { |
484 | test_id: Path( | 747 | test_id: Path( |
485 | "test_foo1", | 748 | "test_foo1", |
@@ -498,6 +761,7 @@ mod tests { | |||
498 | ] | 761 | ] |
499 | "### | 762 | "### |
500 | ); | 763 | ); |
764 | assert_actions(&runnables, &[&TEST]); | ||
501 | } | 765 | } |
502 | 766 | ||
503 | #[test] | 767 | #[test] |
@@ -516,7 +780,20 @@ mod tests { | |||
516 | @r###" | 780 | @r###" |
517 | [ | 781 | [ |
518 | Runnable { | 782 | Runnable { |
519 | range: 1..80, | 783 | nav: NavigationTarget { |
784 | file_id: FileId( | ||
785 | 1, | ||
786 | ), | ||
787 | full_range: 1..80, | ||
788 | name: "test_foo1", | ||
789 | kind: FN_DEF, | ||
790 | focus_range: Some( | ||
791 | 66..75, | ||
792 | ), | ||
793 | container_name: None, | ||
794 | description: None, | ||
795 | docs: None, | ||
796 | }, | ||
520 | kind: Test { | 797 | kind: Test { |
521 | test_id: Path( | 798 | test_id: Path( |
522 | "test_foo1", | 799 | "test_foo1", |
@@ -543,6 +820,7 @@ mod tests { | |||
543 | ] | 820 | ] |
544 | "### | 821 | "### |
545 | ); | 822 | ); |
823 | assert_actions(&runnables, &[&TEST]); | ||
546 | } | 824 | } |
547 | 825 | ||
548 | #[test] | 826 | #[test] |
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html new file mode 100644 index 000000000..0ae8c7efc --- /dev/null +++ b/crates/ra_ide/src/snapshots/highlight_doctest.html | |||
@@ -0,0 +1,71 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | ||
8 | .struct, .enum { color: #7CB8BB; } | ||
9 | .enum_variant { color: #BDE0F3; } | ||
10 | .string_literal { color: #CC9393; } | ||
11 | .field { color: #94BFF3; } | ||
12 | .function { color: #93E0E3; } | ||
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
15 | .parameter { color: #94BFF3; } | ||
16 | .text { color: #DCDCCC; } | ||
17 | .type { color: #7CB8BB; } | ||
18 | .builtin_type { color: #8CD0D3; } | ||
19 | .type_param { color: #DFAF8F; } | ||
20 | .attribute { color: #94BFF3; } | ||
21 | .numeric_literal { color: #BFEBBF; } | ||
22 | .bool_literal { color: #BFE6EB; } | ||
23 | .macro { color: #94BFF3; } | ||
24 | .module { color: #AFD8AF; } | ||
25 | .variable { color: #DCDCCC; } | ||
26 | .format_specifier { color: #CC696B; } | ||
27 | .mutable { text-decoration: underline; } | ||
28 | |||
29 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
30 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
31 | .control { font-style: italic; } | ||
32 | </style> | ||
33 | <pre><code><span class="keyword">impl</span> <span class="unresolved_reference">Foo</span> { | ||
34 | <span class="comment">/// Constructs a new `Foo`.</span> | ||
35 | <span class="comment">///</span> | ||
36 | <span class="comment">/// # Examples</span> | ||
37 | <span class="comment">///</span> | ||
38 | <span class="comment">/// ```</span> | ||
39 | <span class="comment">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span> | ||
40 | <span class="comment">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="unresolved_reference">Foo</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>(); | ||
41 | <span class="comment">/// ```</span> | ||
42 | <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -> <span class="unresolved_reference">Foo</span> { | ||
43 | <span class="unresolved_reference">Foo</span> { } | ||
44 | } | ||
45 | |||
46 | <span class="comment">/// `bar` method on `Foo`.</span> | ||
47 | <span class="comment">///</span> | ||
48 | <span class="comment">/// # Examples</span> | ||
49 | <span class="comment">///</span> | ||
50 | <span class="comment">/// ```</span> | ||
51 | <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>(); | ||
52 | <span class="comment">///</span> | ||
53 | <span class="comment">/// </span><span class="comment">// calls bar on foo</span> | ||
54 | <span class="comment">/// </span><span class="macro">assert!</span>(foo.bar()); | ||
55 | <span class="comment">///</span> | ||
56 | <span class="comment">/// </span><span class="comment">/* multi-line | ||
57 | </span><span class="comment">/// </span><span class="comment"> comment */</span> | ||
58 | <span class="comment">///</span> | ||
59 | <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">multi_line_string</span> = <span class="string_literal">"Foo | ||
60 | </span><span class="comment">/// </span><span class="string_literal"> bar | ||
61 | </span><span class="comment">/// </span><span class="string_literal"> "</span>; | ||
62 | <span class="comment">///</span> | ||
63 | <span class="comment">/// ```</span> | ||
64 | <span class="comment">///</span> | ||
65 | <span class="comment">/// ```</span> | ||
66 | <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="unresolved_reference">Foo</span>::<span class="unresolved_reference">new</span>().<span class="unresolved_reference">bar</span>(); | ||
67 | <span class="comment">/// ```</span> | ||
68 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -> <span class="builtin_type">bool</span> { | ||
69 | <span class="bool_literal">true</span> | ||
70 | } | ||
71 | }</code></pre> \ No newline at end of file | ||
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html index 68fc589bc..dec06eb51 100644 --- a/crates/ra_ide/src/snapshots/highlight_injection.html +++ b/crates/ra_ide/src/snapshots/highlight_injection.html | |||
@@ -10,6 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
10 | .string_literal { color: #CC9393; } | 10 | .string_literal { color: #CC9393; } |
11 | .field { color: #94BFF3; } | 11 | .field { color: #94BFF3; } |
12 | .function { color: #93E0E3; } | 12 | .function { color: #93E0E3; } |
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
13 | .parameter { color: #94BFF3; } | 15 | .parameter { color: #94BFF3; } |
14 | .text { color: #DCDCCC; } | 16 | .text { color: #DCDCCC; } |
15 | .type { color: #7CB8BB; } | 17 | .type { color: #7CB8BB; } |
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html index 326744361..849eb3b73 100644 --- a/crates/ra_ide/src/snapshots/highlight_strings.html +++ b/crates/ra_ide/src/snapshots/highlight_strings.html | |||
@@ -10,6 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
10 | .string_literal { color: #CC9393; } | 10 | .string_literal { color: #CC9393; } |
11 | .field { color: #94BFF3; } | 11 | .field { color: #94BFF3; } |
12 | .function { color: #93E0E3; } | 12 | .function { color: #93E0E3; } |
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
13 | .parameter { color: #94BFF3; } | 15 | .parameter { color: #94BFF3; } |
14 | .text { color: #DCDCCC; } | 16 | .text { color: #DCDCCC; } |
15 | .type { color: #7CB8BB; } | 17 | .type { color: #7CB8BB; } |
@@ -52,6 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
52 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> | 54 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// => "test"</span> |
53 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> | 55 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// => "2 1"</span> |
54 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> | 56 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// => "a 3 b"</span> |
57 | <span class="macro">println!</span>(<span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span>, <span class="numeric_literal">2</span>); <span class="comment">// => "{2}"</span> | ||
55 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 58 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
56 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); | 59 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); |
57 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); | 60 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); |
@@ -61,7 +64,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
61 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 64 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
62 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); | 65 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); |
63 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); | 66 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); |
64 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>); | 67 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); |
65 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); | 68 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); |
66 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); | 69 | <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); |
67 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); | 70 | <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); |
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html new file mode 100644 index 000000000..bd24e6e38 --- /dev/null +++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html | |||
@@ -0,0 +1,49 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | ||
8 | .struct, .enum { color: #7CB8BB; } | ||
9 | .enum_variant { color: #BDE0F3; } | ||
10 | .string_literal { color: #CC9393; } | ||
11 | .field { color: #94BFF3; } | ||
12 | .function { color: #93E0E3; } | ||
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
15 | .parameter { color: #94BFF3; } | ||
16 | .text { color: #DCDCCC; } | ||
17 | .type { color: #7CB8BB; } | ||
18 | .builtin_type { color: #8CD0D3; } | ||
19 | .type_param { color: #DFAF8F; } | ||
20 | .attribute { color: #94BFF3; } | ||
21 | .numeric_literal { color: #BFEBBF; } | ||
22 | .bool_literal { color: #BFE6EB; } | ||
23 | .macro { color: #94BFF3; } | ||
24 | .module { color: #AFD8AF; } | ||
25 | .variable { color: #DCDCCC; } | ||
26 | .format_specifier { color: #CC696B; } | ||
27 | .mutable { text-decoration: underline; } | ||
28 | |||
29 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
30 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
31 | .control { font-style: italic; } | ||
32 | </style> | ||
33 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span>() {} | ||
34 | |||
35 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span>; | ||
36 | |||
37 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> { | ||
38 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span>(&<span class="self_keyword">self</span>) {} | ||
39 | } | ||
40 | |||
41 | <span class="keyword">fn</span> <span class="function declaration">main</span>() { | ||
42 | <span class="keyword">let</span> <span class="variable declaration">x</span> = &<span class="numeric_literal">5</span> <span class="keyword">as</span> *<span class="keyword">const</span> <span class="builtin_type">usize</span>; | ||
43 | <span class="keyword unsafe">unsafe</span> { | ||
44 | <span class="function unsafe">unsafe_fn</span>(); | ||
45 | <span class="struct">HasUnsafeFn</span>.<span class="function unsafe">unsafe_method</span>(); | ||
46 | <span class="keyword">let</span> <span class="variable declaration">y</span> = <span class="operator unsafe">*</span>(<span class="variable">x</span>); | ||
47 | <span class="keyword">let</span> <span class="variable declaration">z</span> = -<span class="variable">x</span>; | ||
48 | } | ||
49 | }</code></pre> \ No newline at end of file | ||
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 352e35095..33548d43c 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -10,6 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
10 | .string_literal { color: #CC9393; } | 10 | .string_literal { color: #CC9393; } |
11 | .field { color: #94BFF3; } | 11 | .field { color: #94BFF3; } |
12 | .function { color: #93E0E3; } | 12 | .function { color: #93E0E3; } |
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
13 | .parameter { color: #94BFF3; } | 15 | .parameter { color: #94BFF3; } |
14 | .text { color: #DCDCCC; } | 16 | .text { color: #DCDCCC; } |
15 | .type { color: #7CB8BB; } | 17 | .type { color: #7CB8BB; } |
@@ -82,7 +84,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
82 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; | 84 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; |
83 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; | 85 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; |
84 | 86 | ||
85 | <span class="variable mutable">y</span>; | 87 | <span class="keyword">let</span> <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable declaration">z</span>, <span class="field">y</span> } = <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable">z</span>, <span class="field">y</span> }; |
88 | |||
89 | <span class="variable">y</span>; | ||
86 | } | 90 | } |
87 | 91 | ||
88 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><<span class="type_param declaration">T</span>> { | 92 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><<span class="type_param declaration">T</span>> { |
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 2a0294f71..1ab06182c 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html | |||
@@ -10,6 +10,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
10 | .string_literal { color: #CC9393; } | 10 | .string_literal { color: #CC9393; } |
11 | .field { color: #94BFF3; } | 11 | .field { color: #94BFF3; } |
12 | .function { color: #93E0E3; } | 12 | .function { color: #93E0E3; } |
13 | .function.unsafe { color: #BC8383; } | ||
14 | .operator.unsafe { color: #BC8383; } | ||
13 | .parameter { color: #94BFF3; } | 15 | .parameter { color: #94BFF3; } |
14 | .text { color: #DCDCCC; } | 16 | .text { color: #DCDCCC; } |
15 | .type { color: #7CB8BB; } | 17 | .type { color: #7CB8BB; } |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 0b53ebe69..ab45c364a 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | mod tags; | 1 | mod tags; |
2 | mod html; | 2 | mod html; |
3 | mod injection; | ||
3 | #[cfg(test)] | 4 | #[cfg(test)] |
4 | mod tests; | 5 | mod tests; |
5 | 6 | ||
@@ -10,14 +11,14 @@ use ra_ide_db::{ | |||
10 | }; | 11 | }; |
11 | use ra_prof::profile; | 12 | use ra_prof::profile; |
12 | use ra_syntax::{ | 13 | use ra_syntax::{ |
13 | ast::{self, HasFormatSpecifier, HasQuotes, HasStringValue}, | 14 | ast::{self, HasFormatSpecifier}, |
14 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, | 15 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, |
15 | SyntaxKind::*, | 16 | SyntaxKind::*, |
16 | SyntaxToken, TextRange, WalkEvent, T, | 17 | TextRange, WalkEvent, T, |
17 | }; | 18 | }; |
18 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::FxHashMap; |
19 | 20 | ||
20 | use crate::{call_info::ActiveParameter, Analysis, FileId}; | 21 | use crate::FileId; |
21 | 22 | ||
22 | use ast::FormatSpecifier; | 23 | use ast::FormatSpecifier; |
23 | pub(crate) use html::highlight_as_html; | 24 | pub(crate) use html::highlight_as_html; |
@@ -123,6 +124,23 @@ pub(crate) fn highlight( | |||
123 | _ => (), | 124 | _ => (), |
124 | } | 125 | } |
125 | 126 | ||
127 | // Check for Rust code in documentation | ||
128 | match &event { | ||
129 | WalkEvent::Leave(NodeOrToken::Node(node)) => { | ||
130 | if let Some((doctest, range_mapping, new_comments)) = | ||
131 | injection::extract_doc_comments(node) | ||
132 | { | ||
133 | injection::highlight_doc_comment( | ||
134 | doctest, | ||
135 | range_mapping, | ||
136 | new_comments, | ||
137 | &mut stack, | ||
138 | ); | ||
139 | } | ||
140 | } | ||
141 | _ => (), | ||
142 | } | ||
143 | |||
126 | let element = match event { | 144 | let element = match event { |
127 | WalkEvent::Enter(it) => it, | 145 | WalkEvent::Enter(it) => it, |
128 | WalkEvent::Leave(_) => continue, | 146 | WalkEvent::Leave(_) => continue, |
@@ -173,7 +191,7 @@ pub(crate) fn highlight( | |||
173 | 191 | ||
174 | if let Some(token) = element.as_token().cloned().and_then(ast::RawString::cast) { | 192 | if let Some(token) = element.as_token().cloned().and_then(ast::RawString::cast) { |
175 | let expanded = element_to_highlight.as_token().unwrap().clone(); | 193 | let expanded = element_to_highlight.as_token().unwrap().clone(); |
176 | if highlight_injection(&mut stack, &sema, token, expanded).is_some() { | 194 | if injection::highlight_injection(&mut stack, &sema, token, expanded).is_some() { |
177 | continue; | 195 | continue; |
178 | } | 196 | } |
179 | } | 197 | } |
@@ -259,9 +277,8 @@ impl HighlightedRangeStack { | |||
259 | let mut parent = prev.pop().unwrap(); | 277 | let mut parent = prev.pop().unwrap(); |
260 | for ele in children { | 278 | for ele in children { |
261 | assert!(parent.range.contains_range(ele.range)); | 279 | assert!(parent.range.contains_range(ele.range)); |
262 | let mut cloned = parent.clone(); | 280 | |
263 | parent.range = TextRange::new(parent.range.start(), ele.range.start()); | 281 | let cloned = Self::intersect(&mut parent, &ele); |
264 | cloned.range = TextRange::new(ele.range.end(), cloned.range.end()); | ||
265 | if !parent.range.is_empty() { | 282 | if !parent.range.is_empty() { |
266 | prev.push(parent); | 283 | prev.push(parent); |
267 | } | 284 | } |
@@ -274,6 +291,62 @@ impl HighlightedRangeStack { | |||
274 | } | 291 | } |
275 | } | 292 | } |
276 | 293 | ||
294 | /// Intersects the `HighlightedRange` `parent` with `child`. | ||
295 | /// `parent` is mutated in place, becoming the range before `child`. | ||
296 | /// Returns the range (of the same type as `parent`) *after* `child`. | ||
297 | fn intersect(parent: &mut HighlightedRange, child: &HighlightedRange) -> HighlightedRange { | ||
298 | assert!(parent.range.contains_range(child.range)); | ||
299 | |||
300 | let mut cloned = parent.clone(); | ||
301 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
302 | cloned.range = TextRange::new(child.range.end(), cloned.range.end()); | ||
303 | |||
304 | cloned | ||
305 | } | ||
306 | |||
307 | /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) | ||
308 | /// can only modify the last range currently on the stack. | ||
309 | /// Can be used to do injections that span multiple ranges, like the | ||
310 | /// doctest injection below. | ||
311 | /// If `delete` is set to true, the parent range is deleted instead of | ||
312 | /// intersected. | ||
313 | /// | ||
314 | /// Note that `pop` can be simulated by `pop_and_inject(false)` but the | ||
315 | /// latter is computationally more expensive. | ||
316 | fn pop_and_inject(&mut self, delete: bool) { | ||
317 | let mut children = self.stack.pop().unwrap(); | ||
318 | let prev = self.stack.last_mut().unwrap(); | ||
319 | children.sort_by_key(|range| range.range.start()); | ||
320 | prev.sort_by_key(|range| range.range.start()); | ||
321 | |||
322 | for child in children { | ||
323 | if let Some(idx) = | ||
324 | prev.iter().position(|parent| parent.range.contains_range(child.range)) | ||
325 | { | ||
326 | let cloned = Self::intersect(&mut prev[idx], &child); | ||
327 | let insert_idx = if delete || prev[idx].range.is_empty() { | ||
328 | prev.remove(idx); | ||
329 | idx | ||
330 | } else { | ||
331 | idx + 1 | ||
332 | }; | ||
333 | prev.insert(insert_idx, child); | ||
334 | if !delete && !cloned.range.is_empty() { | ||
335 | prev.insert(insert_idx + 1, cloned); | ||
336 | } | ||
337 | } else if let Some(_idx) = | ||
338 | prev.iter().position(|parent| parent.range.contains(child.range.start())) | ||
339 | { | ||
340 | unreachable!("child range should be completely contained in parent range"); | ||
341 | } else { | ||
342 | let idx = prev | ||
343 | .binary_search_by_key(&child.range.start(), |range| range.range.start()) | ||
344 | .unwrap_or_else(|x| x); | ||
345 | prev.insert(idx, child); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
277 | fn add(&mut self, range: HighlightedRange) { | 350 | fn add(&mut self, range: HighlightedRange) { |
278 | self.stack | 351 | self.stack |
279 | .last_mut() | 352 | .last_mut() |
@@ -363,6 +436,7 @@ fn highlight_element( | |||
363 | highlight_name(db, def) | HighlightModifier::Definition | 436 | highlight_name(db, def) | HighlightModifier::Definition |
364 | } | 437 | } |
365 | Some(NameClass::ConstReference(def)) => highlight_name(db, def), | 438 | Some(NameClass::ConstReference(def)) => highlight_name(db, def), |
439 | Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(), | ||
366 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, | 440 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, |
367 | } | 441 | } |
368 | } | 442 | } |
@@ -406,6 +480,19 @@ fn highlight_element( | |||
406 | _ => h, | 480 | _ => h, |
407 | } | 481 | } |
408 | } | 482 | } |
483 | T![*] => { | ||
484 | let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; | ||
485 | |||
486 | let expr = prefix_expr.expr()?; | ||
487 | let ty = sema.type_of_expr(&expr)?; | ||
488 | if !ty.is_raw_ptr() { | ||
489 | return None; | ||
490 | } | ||
491 | |||
492 | let mut h = Highlight::new(HighlightTag::Operator); | ||
493 | h |= HighlightModifier::Unsafe; | ||
494 | h | ||
495 | } | ||
409 | 496 | ||
410 | k if k.is_keyword() => { | 497 | k if k.is_keyword() => { |
411 | let h = Highlight::new(HighlightTag::Keyword); | 498 | let h = Highlight::new(HighlightTag::Keyword); |
@@ -458,7 +545,13 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { | |||
458 | Definition::Field(_) => HighlightTag::Field, | 545 | Definition::Field(_) => HighlightTag::Field, |
459 | Definition::ModuleDef(def) => match def { | 546 | Definition::ModuleDef(def) => match def { |
460 | hir::ModuleDef::Module(_) => HighlightTag::Module, | 547 | hir::ModuleDef::Module(_) => HighlightTag::Module, |
461 | hir::ModuleDef::Function(_) => HighlightTag::Function, | 548 | hir::ModuleDef::Function(func) => { |
549 | let mut h = HighlightTag::Function.into(); | ||
550 | if func.is_unsafe(db) { | ||
551 | h |= HighlightModifier::Unsafe; | ||
552 | } | ||
553 | return h; | ||
554 | } | ||
462 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, | 555 | hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, |
463 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, | 556 | hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, |
464 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union, | 557 | hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union, |
@@ -516,42 +609,3 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | |||
516 | 609 | ||
517 | tag.into() | 610 | tag.into() |
518 | } | 611 | } |
519 | |||
520 | fn highlight_injection( | ||
521 | acc: &mut HighlightedRangeStack, | ||
522 | sema: &Semantics<RootDatabase>, | ||
523 | literal: ast::RawString, | ||
524 | expanded: SyntaxToken, | ||
525 | ) -> Option<()> { | ||
526 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
527 | if !active_parameter.name.starts_with("ra_fixture") { | ||
528 | return None; | ||
529 | } | ||
530 | let value = literal.value()?; | ||
531 | let (analysis, tmp_file_id) = Analysis::from_single_file(value); | ||
532 | |||
533 | if let Some(range) = literal.open_quote_text_range() { | ||
534 | acc.add(HighlightedRange { | ||
535 | range, | ||
536 | highlight: HighlightTag::StringLiteral.into(), | ||
537 | binding_hash: None, | ||
538 | }) | ||
539 | } | ||
540 | |||
541 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | ||
542 | if let Some(r) = literal.map_range_up(h.range) { | ||
543 | h.range = r; | ||
544 | acc.add(h) | ||
545 | } | ||
546 | } | ||
547 | |||
548 | if let Some(range) = literal.close_quote_text_range() { | ||
549 | acc.add(HighlightedRange { | ||
550 | range, | ||
551 | highlight: HighlightTag::StringLiteral.into(), | ||
552 | binding_hash: None, | ||
553 | }) | ||
554 | } | ||
555 | |||
556 | Some(()) | ||
557 | } | ||
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index edfe61f39..5bada6252 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs | |||
@@ -69,6 +69,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
69 | .string_literal { color: #CC9393; } | 69 | .string_literal { color: #CC9393; } |
70 | .field { color: #94BFF3; } | 70 | .field { color: #94BFF3; } |
71 | .function { color: #93E0E3; } | 71 | .function { color: #93E0E3; } |
72 | .function.unsafe { color: #BC8383; } | ||
73 | .operator.unsafe { color: #BC8383; } | ||
72 | .parameter { color: #94BFF3; } | 74 | .parameter { color: #94BFF3; } |
73 | .text { color: #DCDCCC; } | 75 | .text { color: #DCDCCC; } |
74 | .type { color: #7CB8BB; } | 76 | .type { color: #7CB8BB; } |
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs new file mode 100644 index 000000000..3575a0fc6 --- /dev/null +++ b/crates/ra_ide/src/syntax_highlighting/injection.rs | |||
@@ -0,0 +1,168 @@ | |||
1 | //! Syntax highlighting injections such as highlighting of documentation tests. | ||
2 | |||
3 | use std::{collections::BTreeMap, convert::TryFrom}; | ||
4 | |||
5 | use ast::{HasQuotes, HasStringValue}; | ||
6 | use hir::Semantics; | ||
7 | use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
8 | use stdx::SepBy; | ||
9 | |||
10 | use crate::{call_info::ActiveParameter, Analysis, HighlightTag, HighlightedRange, RootDatabase}; | ||
11 | |||
12 | use super::HighlightedRangeStack; | ||
13 | |||
14 | pub(super) fn highlight_injection( | ||
15 | acc: &mut HighlightedRangeStack, | ||
16 | sema: &Semantics<RootDatabase>, | ||
17 | literal: ast::RawString, | ||
18 | expanded: SyntaxToken, | ||
19 | ) -> Option<()> { | ||
20 | let active_parameter = ActiveParameter::at_token(&sema, expanded)?; | ||
21 | if !active_parameter.name.starts_with("ra_fixture") { | ||
22 | return None; | ||
23 | } | ||
24 | let value = literal.value()?; | ||
25 | let (analysis, tmp_file_id) = Analysis::from_single_file(value); | ||
26 | |||
27 | if let Some(range) = literal.open_quote_text_range() { | ||
28 | acc.add(HighlightedRange { | ||
29 | range, | ||
30 | highlight: HighlightTag::StringLiteral.into(), | ||
31 | binding_hash: None, | ||
32 | }) | ||
33 | } | ||
34 | |||
35 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | ||
36 | if let Some(r) = literal.map_range_up(h.range) { | ||
37 | h.range = r; | ||
38 | acc.add(h) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | if let Some(range) = literal.close_quote_text_range() { | ||
43 | acc.add(HighlightedRange { | ||
44 | range, | ||
45 | highlight: HighlightTag::StringLiteral.into(), | ||
46 | binding_hash: None, | ||
47 | }) | ||
48 | } | ||
49 | |||
50 | Some(()) | ||
51 | } | ||
52 | |||
53 | /// Mapping from extracted documentation code to original code | ||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | ||
55 | |||
56 | /// Extracts Rust code from documentation comments as well as a mapping from | ||
57 | /// the extracted source code back to the original source ranges. | ||
58 | /// Lastly, a vector of new comment highlight ranges (spanning only the | ||
59 | /// comment prefix) is returned which is used in the syntax highlighting | ||
60 | /// injection to replace the previous (line-spanning) comment ranges. | ||
61 | pub(super) fn extract_doc_comments( | ||
62 | node: &SyntaxNode, | ||
63 | ) -> Option<(String, RangesMap, Vec<HighlightedRange>)> { | ||
64 | // wrap the doctest into function body to get correct syntax highlighting | ||
65 | let prefix = "fn doctest() {\n"; | ||
66 | let suffix = "}\n"; | ||
67 | // Mapping from extracted documentation code to original code | ||
68 | let mut range_mapping: RangesMap = BTreeMap::new(); | ||
69 | let mut line_start = TextSize::try_from(prefix.len()).unwrap(); | ||
70 | let mut is_doctest = false; | ||
71 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | ||
72 | // spanning comment ranges. | ||
73 | let mut new_comments = Vec::new(); | ||
74 | let doctest = node | ||
75 | .children_with_tokens() | ||
76 | .filter_map(|el| el.into_token().and_then(ast::Comment::cast)) | ||
77 | .filter(|comment| comment.kind().doc.is_some()) | ||
78 | .filter(|comment| { | ||
79 | if comment.text().contains("```") { | ||
80 | is_doctest = !is_doctest; | ||
81 | false | ||
82 | } else { | ||
83 | is_doctest | ||
84 | } | ||
85 | }) | ||
86 | .map(|comment| { | ||
87 | let prefix_len = comment.prefix().len(); | ||
88 | let line: &str = comment.text().as_str(); | ||
89 | let range = comment.syntax().text_range(); | ||
90 | |||
91 | // whitespace after comment is ignored | ||
92 | let pos = if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) { | ||
93 | prefix_len + ws.len_utf8() | ||
94 | } else { | ||
95 | prefix_len | ||
96 | }; | ||
97 | |||
98 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
99 | let pos = if let Some(ws) = line.chars().nth(pos).filter(|&c| c == '#') { | ||
100 | pos + ws.len_utf8() | ||
101 | } else { | ||
102 | pos | ||
103 | }; | ||
104 | |||
105 | range_mapping.insert(line_start, range.start() + TextSize::try_from(pos).unwrap()); | ||
106 | new_comments.push(HighlightedRange { | ||
107 | range: TextRange::new( | ||
108 | range.start(), | ||
109 | range.start() + TextSize::try_from(pos).unwrap(), | ||
110 | ), | ||
111 | highlight: HighlightTag::Comment.into(), | ||
112 | binding_hash: None, | ||
113 | }); | ||
114 | line_start += range.len() - TextSize::try_from(pos).unwrap(); | ||
115 | line_start += TextSize::try_from('\n'.len_utf8()).unwrap(); | ||
116 | |||
117 | line[pos..].to_owned() | ||
118 | }) | ||
119 | .sep_by("\n") | ||
120 | .to_string(); | ||
121 | |||
122 | if doctest.is_empty() { | ||
123 | return None; | ||
124 | } | ||
125 | |||
126 | let doctest = format!("{}{}{}", prefix, doctest, suffix); | ||
127 | Some((doctest, range_mapping, new_comments)) | ||
128 | } | ||
129 | |||
130 | /// Injection of syntax highlighting of doctests. | ||
131 | pub(super) fn highlight_doc_comment( | ||
132 | text: String, | ||
133 | range_mapping: RangesMap, | ||
134 | new_comments: Vec<HighlightedRange>, | ||
135 | stack: &mut HighlightedRangeStack, | ||
136 | ) { | ||
137 | let (analysis, tmp_file_id) = Analysis::from_single_file(text); | ||
138 | |||
139 | stack.push(); | ||
140 | for mut h in analysis.highlight(tmp_file_id).unwrap() { | ||
141 | // Determine start offset and end offset in case of multi-line ranges | ||
142 | let mut start_offset = None; | ||
143 | let mut end_offset = None; | ||
144 | for (line_start, orig_line_start) in range_mapping.range(..h.range.end()).rev() { | ||
145 | if line_start <= &h.range.start() { | ||
146 | start_offset.get_or_insert(orig_line_start - line_start); | ||
147 | break; | ||
148 | } else { | ||
149 | end_offset.get_or_insert(orig_line_start - line_start); | ||
150 | } | ||
151 | } | ||
152 | if let Some(start_offset) = start_offset { | ||
153 | h.range = TextRange::new( | ||
154 | h.range.start() + start_offset, | ||
155 | h.range.end() + end_offset.unwrap_or(start_offset), | ||
156 | ); | ||
157 | stack.add(h); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // Inject the comment prefix highlight ranges | ||
162 | stack.push(); | ||
163 | for comment in new_comments { | ||
164 | stack.add(comment); | ||
165 | } | ||
166 | stack.pop_and_inject(false); | ||
167 | stack.pop_and_inject(true); | ||
168 | } | ||
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs index 1514531de..94f466966 100644 --- a/crates/ra_ide/src/syntax_highlighting/tags.rs +++ b/crates/ra_ide/src/syntax_highlighting/tags.rs | |||
@@ -24,12 +24,14 @@ pub enum HighlightTag { | |||
24 | Enum, | 24 | Enum, |
25 | EnumVariant, | 25 | EnumVariant, |
26 | Field, | 26 | Field, |
27 | FormatSpecifier, | ||
27 | Function, | 28 | Function, |
28 | Keyword, | 29 | Keyword, |
29 | Lifetime, | 30 | Lifetime, |
30 | Macro, | 31 | Macro, |
31 | Module, | 32 | Module, |
32 | NumericLiteral, | 33 | NumericLiteral, |
34 | Operator, | ||
33 | SelfKeyword, | 35 | SelfKeyword, |
34 | SelfType, | 36 | SelfType, |
35 | Static, | 37 | Static, |
@@ -41,8 +43,6 @@ pub enum HighlightTag { | |||
41 | Union, | 43 | Union, |
42 | Local, | 44 | Local, |
43 | UnresolvedReference, | 45 | UnresolvedReference, |
44 | FormatSpecifier, | ||
45 | Operator, | ||
46 | } | 46 | } |
47 | 47 | ||
48 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | 48 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] |
@@ -72,12 +72,14 @@ impl HighlightTag { | |||
72 | HighlightTag::Enum => "enum", | 72 | HighlightTag::Enum => "enum", |
73 | HighlightTag::EnumVariant => "enum_variant", | 73 | HighlightTag::EnumVariant => "enum_variant", |
74 | HighlightTag::Field => "field", | 74 | HighlightTag::Field => "field", |
75 | HighlightTag::FormatSpecifier => "format_specifier", | ||
75 | HighlightTag::Function => "function", | 76 | HighlightTag::Function => "function", |
76 | HighlightTag::Keyword => "keyword", | 77 | HighlightTag::Keyword => "keyword", |
77 | HighlightTag::Lifetime => "lifetime", | 78 | HighlightTag::Lifetime => "lifetime", |
78 | HighlightTag::Macro => "macro", | 79 | HighlightTag::Macro => "macro", |
79 | HighlightTag::Module => "module", | 80 | HighlightTag::Module => "module", |
80 | HighlightTag::NumericLiteral => "numeric_literal", | 81 | HighlightTag::NumericLiteral => "numeric_literal", |
82 | HighlightTag::Operator => "operator", | ||
81 | HighlightTag::SelfKeyword => "self_keyword", | 83 | HighlightTag::SelfKeyword => "self_keyword", |
82 | HighlightTag::SelfType => "self_type", | 84 | HighlightTag::SelfType => "self_type", |
83 | HighlightTag::Static => "static", | 85 | HighlightTag::Static => "static", |
@@ -89,8 +91,6 @@ impl HighlightTag { | |||
89 | HighlightTag::Union => "union", | 91 | HighlightTag::Union => "union", |
90 | HighlightTag::Local => "variable", | 92 | HighlightTag::Local => "variable", |
91 | HighlightTag::UnresolvedReference => "unresolved_reference", | 93 | HighlightTag::UnresolvedReference => "unresolved_reference", |
92 | HighlightTag::FormatSpecifier => "format_specifier", | ||
93 | HighlightTag::Operator => "operator", | ||
94 | } | 94 | } |
95 | } | 95 | } |
96 | } | 96 | } |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index eb43a23da..949bf59a0 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -9,7 +9,7 @@ use crate::{ | |||
9 | 9 | ||
10 | #[test] | 10 | #[test] |
11 | fn test_highlighting() { | 11 | fn test_highlighting() { |
12 | let (analysis, file_id) = single_file( | 12 | check_highlighting( |
13 | r#" | 13 | r#" |
14 | #[derive(Clone, Debug)] | 14 | #[derive(Clone, Debug)] |
15 | struct Foo { | 15 | struct Foo { |
@@ -65,6 +65,8 @@ fn main() { | |||
65 | let y = &mut x; | 65 | let y = &mut x; |
66 | let z = &y; | 66 | let z = &y; |
67 | 67 | ||
68 | let Foo { x: z, y } = Foo { x: z, y }; | ||
69 | |||
68 | y; | 70 | y; |
69 | } | 71 | } |
70 | 72 | ||
@@ -84,17 +86,14 @@ impl<T> Option<T> { | |||
84 | } | 86 | } |
85 | "# | 87 | "# |
86 | .trim(), | 88 | .trim(), |
89 | "crates/ra_ide/src/snapshots/highlighting.html", | ||
90 | false, | ||
87 | ); | 91 | ); |
88 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html"); | ||
89 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); | ||
90 | let expected_html = &read_text(&dst_file); | ||
91 | fs::write(dst_file, &actual_html).unwrap(); | ||
92 | assert_eq_text!(expected_html, actual_html); | ||
93 | } | 92 | } |
94 | 93 | ||
95 | #[test] | 94 | #[test] |
96 | fn test_rainbow_highlighting() { | 95 | fn test_rainbow_highlighting() { |
97 | let (analysis, file_id) = single_file( | 96 | check_highlighting( |
98 | r#" | 97 | r#" |
99 | fn main() { | 98 | fn main() { |
100 | let hello = "hello"; | 99 | let hello = "hello"; |
@@ -110,12 +109,9 @@ fn bar() { | |||
110 | } | 109 | } |
111 | "# | 110 | "# |
112 | .trim(), | 111 | .trim(), |
112 | "crates/ra_ide/src/snapshots/rainbow_highlighting.html", | ||
113 | true, | ||
113 | ); | 114 | ); |
114 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html"); | ||
115 | let actual_html = &analysis.highlight_as_html(file_id, true).unwrap(); | ||
116 | let expected_html = &read_text(&dst_file); | ||
117 | fs::write(dst_file, &actual_html).unwrap(); | ||
118 | assert_eq_text!(expected_html, actual_html); | ||
119 | } | 115 | } |
120 | 116 | ||
121 | #[test] | 117 | #[test] |
@@ -153,7 +149,7 @@ fn test_ranges() { | |||
153 | 149 | ||
154 | #[test] | 150 | #[test] |
155 | fn test_flattening() { | 151 | fn test_flattening() { |
156 | let (analysis, file_id) = single_file( | 152 | check_highlighting( |
157 | r##" | 153 | r##" |
158 | fn fixture(ra_fixture: &str) {} | 154 | fn fixture(ra_fixture: &str) {} |
159 | 155 | ||
@@ -167,13 +163,9 @@ fn main() { | |||
167 | ); | 163 | ); |
168 | }"## | 164 | }"## |
169 | .trim(), | 165 | .trim(), |
166 | "crates/ra_ide/src/snapshots/highlight_injection.html", | ||
167 | false, | ||
170 | ); | 168 | ); |
171 | |||
172 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_injection.html"); | ||
173 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); | ||
174 | let expected_html = &read_text(&dst_file); | ||
175 | fs::write(dst_file, &actual_html).unwrap(); | ||
176 | assert_eq_text!(expected_html, actual_html); | ||
177 | } | 169 | } |
178 | 170 | ||
179 | #[test] | 171 | #[test] |
@@ -192,7 +184,7 @@ macro_rules! test {} | |||
192 | fn test_string_highlighting() { | 184 | fn test_string_highlighting() { |
193 | // The format string detection is based on macro-expansion, | 185 | // The format string detection is based on macro-expansion, |
194 | // thus, we have to copy the macro definition from `std` | 186 | // thus, we have to copy the macro definition from `std` |
195 | let (analysis, file_id) = single_file( | 187 | check_highlighting( |
196 | r#" | 188 | r#" |
197 | macro_rules! println { | 189 | macro_rules! println { |
198 | ($($arg:tt)*) => ({ | 190 | ($($arg:tt)*) => ({ |
@@ -218,6 +210,7 @@ fn main() { | |||
218 | println!("{argument}", argument = "test"); // => "test" | 210 | println!("{argument}", argument = "test"); // => "test" |
219 | println!("{name} {}", 1, name = 2); // => "2 1" | 211 | println!("{name} {}", 1, name = 2); // => "2 1" |
220 | println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" | 212 | println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" |
213 | println!("{{{}}}", 2); // => "{2}" | ||
221 | println!("Hello {:5}!", "x"); | 214 | println!("Hello {:5}!", "x"); |
222 | println!("Hello {:1$}!", "x", 5); | 215 | println!("Hello {:1$}!", "x", 5); |
223 | println!("Hello {1:0$}!", 5, "x"); | 216 | println!("Hello {1:0$}!", 5, "x"); |
@@ -249,10 +242,96 @@ fn main() { | |||
249 | println!("{ничоси}", ничоси = 92); | 242 | println!("{ничоси}", ничоси = 92); |
250 | }"# | 243 | }"# |
251 | .trim(), | 244 | .trim(), |
245 | "crates/ra_ide/src/snapshots/highlight_strings.html", | ||
246 | false, | ||
252 | ); | 247 | ); |
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn test_unsafe_highlighting() { | ||
252 | check_highlighting( | ||
253 | r#" | ||
254 | unsafe fn unsafe_fn() {} | ||
255 | |||
256 | struct HasUnsafeFn; | ||
257 | |||
258 | impl HasUnsafeFn { | ||
259 | unsafe fn unsafe_method(&self) {} | ||
260 | } | ||
261 | |||
262 | fn main() { | ||
263 | let x = &5 as *const usize; | ||
264 | unsafe { | ||
265 | unsafe_fn(); | ||
266 | HasUnsafeFn.unsafe_method(); | ||
267 | let y = *(x); | ||
268 | let z = -x; | ||
269 | } | ||
270 | } | ||
271 | "# | ||
272 | .trim(), | ||
273 | "crates/ra_ide/src/snapshots/highlight_unsafe.html", | ||
274 | false, | ||
275 | ); | ||
276 | } | ||
277 | |||
278 | #[test] | ||
279 | fn test_highlight_doctest() { | ||
280 | check_highlighting( | ||
281 | r#" | ||
282 | impl Foo { | ||
283 | /// Constructs a new `Foo`. | ||
284 | /// | ||
285 | /// # Examples | ||
286 | /// | ||
287 | /// ``` | ||
288 | /// # #![allow(unused_mut)] | ||
289 | /// let mut foo: Foo = Foo::new(); | ||
290 | /// ``` | ||
291 | pub const fn new() -> Foo { | ||
292 | Foo { } | ||
293 | } | ||
294 | |||
295 | /// `bar` method on `Foo`. | ||
296 | /// | ||
297 | /// # Examples | ||
298 | /// | ||
299 | /// ``` | ||
300 | /// let foo = Foo::new(); | ||
301 | /// | ||
302 | /// // calls bar on foo | ||
303 | /// assert!(foo.bar()); | ||
304 | /// | ||
305 | /// /* multi-line | ||
306 | /// comment */ | ||
307 | /// | ||
308 | /// let multi_line_string = "Foo | ||
309 | /// bar | ||
310 | /// "; | ||
311 | /// | ||
312 | /// ``` | ||
313 | /// | ||
314 | /// ``` | ||
315 | /// let foobar = Foo::new().bar(); | ||
316 | /// ``` | ||
317 | pub fn foo(&self) -> bool { | ||
318 | true | ||
319 | } | ||
320 | } | ||
321 | "# | ||
322 | .trim(), | ||
323 | "crates/ra_ide/src/snapshots/highlight_doctest.html", | ||
324 | false, | ||
325 | ) | ||
326 | } | ||
253 | 327 | ||
254 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_strings.html"); | 328 | /// Highlights the code given by the `ra_fixture` argument, renders the |
255 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); | 329 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
330 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | ||
331 | fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { | ||
332 | let (analysis, file_id) = single_file(ra_fixture); | ||
333 | let dst_file = project_dir().join(snapshot); | ||
334 | let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); | ||
256 | let expected_html = &read_text(&dst_file); | 335 | let expected_html = &read_text(&dst_file); |
257 | fs::write(dst_file, &actual_html).unwrap(); | 336 | fs::write(dst_file, &actual_html).unwrap(); |
258 | assert_eq_text!(expected_html, actual_html); | 337 | assert_eq_text!(expected_html, actual_html); |
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 67e2c33a0..83776d2b6 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -17,11 +17,13 @@ mod on_enter; | |||
17 | 17 | ||
18 | use ra_db::{FilePosition, SourceDatabase}; | 18 | use ra_db::{FilePosition, SourceDatabase}; |
19 | use ra_fmt::leading_indent; | 19 | use ra_fmt::leading_indent; |
20 | use ra_ide_db::RootDatabase; | 20 | use ra_ide_db::{source_change::SourceFileEdit, RootDatabase}; |
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo::find_node_at_offset, | 22 | algo::find_node_at_offset, |
23 | ast::{self, AstToken}, | 23 | ast::{self, AstToken}, |
24 | AstNode, SourceFile, TextRange, TextSize, | 24 | AstNode, SourceFile, |
25 | SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, | ||
26 | TextRange, TextSize, | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | use ra_text_edit::TextEdit; | 29 | use ra_text_edit::TextEdit; |
@@ -47,8 +49,8 @@ pub(crate) fn on_char_typed( | |||
47 | assert!(TRIGGER_CHARS.contains(char_typed)); | 49 | assert!(TRIGGER_CHARS.contains(char_typed)); |
48 | let file = &db.parse(position.file_id).tree(); | 50 | let file = &db.parse(position.file_id).tree(); |
49 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); | 51 | assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); |
50 | let text_edit = on_char_typed_inner(file, position.offset, char_typed)?; | 52 | let edit = on_char_typed_inner(file, position.offset, char_typed)?; |
51 | Some(SourceChange::source_file_edit_from(position.file_id, text_edit)) | 53 | Some(SourceFileEdit { file_id: position.file_id, edit }.into()) |
52 | } | 54 | } |
53 | 55 | ||
54 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { | 56 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { |
@@ -98,9 +100,12 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | |||
98 | }; | 100 | }; |
99 | let current_indent_len = TextSize::of(current_indent); | 101 | let current_indent_len = TextSize::of(current_indent); |
100 | 102 | ||
103 | let parent = whitespace.syntax().parent(); | ||
101 | // Make sure dot is a part of call chain | 104 | // Make sure dot is a part of call chain |
102 | let field_expr = ast::FieldExpr::cast(whitespace.syntax().parent())?; | 105 | if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) { |
103 | let prev_indent = leading_indent(field_expr.syntax())?; | 106 | return None; |
107 | } | ||
108 | let prev_indent = leading_indent(&parent)?; | ||
104 | let target_indent = format!(" {}", prev_indent); | 109 | let target_indent = format!(" {}", prev_indent); |
105 | let target_indent_len = TextSize::of(&target_indent); | 110 | let target_indent_len = TextSize::of(&target_indent); |
106 | if current_indent_len == target_indent_len { | 111 | if current_indent_len == target_indent_len { |
@@ -143,11 +148,11 @@ mod tests { | |||
143 | }) | 148 | }) |
144 | } | 149 | } |
145 | 150 | ||
146 | fn type_char(char_typed: char, before: &str, after: &str) { | 151 | fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) { |
147 | let actual = do_type_char(char_typed, before) | 152 | let actual = do_type_char(char_typed, ra_fixture_before) |
148 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); | 153 | .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); |
149 | 154 | ||
150 | assert_eq_text!(after, &actual); | 155 | assert_eq_text!(ra_fixture_after, &actual); |
151 | } | 156 | } |
152 | 157 | ||
153 | fn type_char_noop(char_typed: char, before: &str) { | 158 | fn type_char_noop(char_typed: char, before: &str) { |
@@ -249,6 +254,27 @@ fn foo() { | |||
249 | } | 254 | } |
250 | 255 | ||
251 | #[test] | 256 | #[test] |
257 | fn indents_new_chain_call_with_let() { | ||
258 | type_char( | ||
259 | '.', | ||
260 | r#" | ||
261 | fn main() { | ||
262 | let _ = foo | ||
263 | <|> | ||
264 | bar() | ||
265 | } | ||
266 | "#, | ||
267 | r#" | ||
268 | fn main() { | ||
269 | let _ = foo | ||
270 | . | ||
271 | bar() | ||
272 | } | ||
273 | "#, | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
252 | fn indents_continued_chain_call() { | 278 | fn indents_continued_chain_call() { |
253 | type_char( | 279 | type_char( |
254 | '.', | 280 | '.', |
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 8446ef88e..2fc796a85 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs | |||
@@ -16,7 +16,7 @@ use rustc_hash::FxHashMap; | |||
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | symbol_index::{SymbolIndex, SymbolsDatabase}, | 18 | symbol_index::{SymbolIndex, SymbolsDatabase}, |
19 | DebugData, RootDatabase, | 19 | RootDatabase, |
20 | }; | 20 | }; |
21 | 21 | ||
22 | #[derive(Default)] | 22 | #[derive(Default)] |
@@ -26,7 +26,6 @@ pub struct AnalysisChange { | |||
26 | files_changed: Vec<(FileId, Arc<String>)>, | 26 | files_changed: Vec<(FileId, Arc<String>)>, |
27 | libraries_added: Vec<LibraryData>, | 27 | libraries_added: Vec<LibraryData>, |
28 | crate_graph: Option<CrateGraph>, | 28 | crate_graph: Option<CrateGraph>, |
29 | debug_data: DebugData, | ||
30 | } | 29 | } |
31 | 30 | ||
32 | impl fmt::Debug for AnalysisChange { | 31 | impl fmt::Debug for AnalysisChange { |
@@ -87,10 +86,6 @@ impl AnalysisChange { | |||
87 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 86 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
88 | self.crate_graph = Some(graph); | 87 | self.crate_graph = Some(graph); |
89 | } | 88 | } |
90 | |||
91 | pub fn set_debug_root_path(&mut self, source_root_id: SourceRootId, path: String) { | ||
92 | self.debug_data.root_paths.insert(source_root_id, path); | ||
93 | } | ||
94 | } | 89 | } |
95 | 90 | ||
96 | #[derive(Debug)] | 91 | #[derive(Debug)] |
@@ -218,8 +213,6 @@ impl RootDatabase { | |||
218 | if let Some(crate_graph) = change.crate_graph { | 213 | if let Some(crate_graph) = change.crate_graph { |
219 | self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) | 214 | self.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) |
220 | } | 215 | } |
221 | |||
222 | Arc::make_mut(&mut self.debug_data).merge(change.debug_data) | ||
223 | } | 216 | } |
224 | 217 | ||
225 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { | 218 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { |
@@ -334,6 +327,7 @@ impl RootDatabase { | |||
334 | hir::db::CrateLangItemsQuery | 327 | hir::db::CrateLangItemsQuery |
335 | hir::db::LangItemQuery | 328 | hir::db::LangItemQuery |
336 | hir::db::DocumentationQuery | 329 | hir::db::DocumentationQuery |
330 | hir::db::ImportMapQuery | ||
337 | 331 | ||
338 | // InternDatabase | 332 | // InternDatabase |
339 | hir::db::InternFunctionQuery | 333 | hir::db::InternFunctionQuery |
@@ -369,6 +363,7 @@ impl RootDatabase { | |||
369 | hir::db::ImplDatumQuery | 363 | hir::db::ImplDatumQuery |
370 | hir::db::AssociatedTyValueQuery | 364 | hir::db::AssociatedTyValueQuery |
371 | hir::db::TraitSolveQuery | 365 | hir::db::TraitSolveQuery |
366 | hir::db::ReturnTypeImplTraitsQuery | ||
372 | 367 | ||
373 | // SymbolsDatabase | 368 | // SymbolsDatabase |
374 | crate::symbol_index::FileSymbolsQuery | 369 | crate::symbol_index::FileSymbolsQuery |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 8b06cbfc5..3ef5e74b6 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -18,7 +18,7 @@ use ra_syntax::{ | |||
18 | use crate::RootDatabase; | 18 | use crate::RootDatabase; |
19 | 19 | ||
20 | // FIXME: a more precise name would probably be `Symbol`? | 20 | // FIXME: a more precise name would probably be `Symbol`? |
21 | #[derive(Debug, PartialEq, Eq)] | 21 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
22 | pub enum Definition { | 22 | pub enum Definition { |
23 | Macro(MacroDef), | 23 | Macro(MacroDef), |
24 | Field(Field), | 24 | Field(Field), |
@@ -78,10 +78,15 @@ impl Definition { | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | #[derive(Debug)] | ||
81 | pub enum NameClass { | 82 | pub enum NameClass { |
82 | Definition(Definition), | 83 | Definition(Definition), |
83 | /// `None` in `if let None = Some(82) {}` | 84 | /// `None` in `if let None = Some(82) {}` |
84 | ConstReference(Definition), | 85 | ConstReference(Definition), |
86 | FieldShorthand { | ||
87 | local: Local, | ||
88 | field: Definition, | ||
89 | }, | ||
85 | } | 90 | } |
86 | 91 | ||
87 | impl NameClass { | 92 | impl NameClass { |
@@ -89,12 +94,14 @@ impl NameClass { | |||
89 | match self { | 94 | match self { |
90 | NameClass::Definition(it) => Some(it), | 95 | NameClass::Definition(it) => Some(it), |
91 | NameClass::ConstReference(_) => None, | 96 | NameClass::ConstReference(_) => None, |
97 | NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)), | ||
92 | } | 98 | } |
93 | } | 99 | } |
94 | 100 | ||
95 | pub fn definition(self) -> Definition { | 101 | pub fn definition(self) -> Definition { |
96 | match self { | 102 | match self { |
97 | NameClass::Definition(it) | NameClass::ConstReference(it) => it, | 103 | NameClass::Definition(it) | NameClass::ConstReference(it) => it, |
104 | NameClass::FieldShorthand { local: _, field } => field, | ||
98 | } | 105 | } |
99 | } | 106 | } |
100 | } | 107 | } |
@@ -102,18 +109,14 @@ impl NameClass { | |||
102 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { | 109 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { |
103 | let _p = profile("classify_name"); | 110 | let _p = profile("classify_name"); |
104 | 111 | ||
105 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { | 112 | let parent = name.syntax().parent()?; |
113 | |||
114 | if let Some(bind_pat) = ast::BindPat::cast(parent.clone()) { | ||
106 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { | 115 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { |
107 | return Some(NameClass::ConstReference(Definition::ModuleDef(def))); | 116 | return Some(NameClass::ConstReference(Definition::ModuleDef(def))); |
108 | } | 117 | } |
109 | } | 118 | } |
110 | 119 | ||
111 | classify_name_inner(sema, name).map(NameClass::Definition) | ||
112 | } | ||
113 | |||
114 | fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Definition> { | ||
115 | let parent = name.syntax().parent()?; | ||
116 | |||
117 | match_ast! { | 120 | match_ast! { |
118 | match parent { | 121 | match parent { |
119 | ast::Alias(it) => { | 122 | ast::Alias(it) => { |
@@ -123,63 +126,73 @@ fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Opti | |||
123 | let name_ref = path_segment.name_ref()?; | 126 | let name_ref = path_segment.name_ref()?; |
124 | let name_ref_class = classify_name_ref(sema, &name_ref)?; | 127 | let name_ref_class = classify_name_ref(sema, &name_ref)?; |
125 | 128 | ||
126 | Some(name_ref_class.definition()) | 129 | Some(NameClass::Definition(name_ref_class.definition())) |
127 | }, | 130 | }, |
128 | ast::BindPat(it) => { | 131 | ast::BindPat(it) => { |
129 | let local = sema.to_def(&it)?; | 132 | let local = sema.to_def(&it)?; |
130 | Some(Definition::Local(local)) | 133 | |
134 | if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordFieldPat::cast) { | ||
135 | if record_field_pat.name_ref().is_none() { | ||
136 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | ||
137 | let field = Definition::Field(field); | ||
138 | return Some(NameClass::FieldShorthand { local, field }); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | Some(NameClass::Definition(Definition::Local(local))) | ||
131 | }, | 144 | }, |
132 | ast::RecordFieldDef(it) => { | 145 | ast::RecordFieldDef(it) => { |
133 | let field: hir::Field = sema.to_def(&it)?; | 146 | let field: hir::Field = sema.to_def(&it)?; |
134 | Some(Definition::Field(field)) | 147 | Some(NameClass::Definition(Definition::Field(field))) |
135 | }, | 148 | }, |
136 | ast::Module(it) => { | 149 | ast::Module(it) => { |
137 | let def = sema.to_def(&it)?; | 150 | let def = sema.to_def(&it)?; |
138 | Some(Definition::ModuleDef(def.into())) | 151 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
139 | }, | 152 | }, |
140 | ast::StructDef(it) => { | 153 | ast::StructDef(it) => { |
141 | let def: hir::Struct = sema.to_def(&it)?; | 154 | let def: hir::Struct = sema.to_def(&it)?; |
142 | Some(Definition::ModuleDef(def.into())) | 155 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
143 | }, | 156 | }, |
144 | ast::UnionDef(it) => { | 157 | ast::UnionDef(it) => { |
145 | let def: hir::Union = sema.to_def(&it)?; | 158 | let def: hir::Union = sema.to_def(&it)?; |
146 | Some(Definition::ModuleDef(def.into())) | 159 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
147 | }, | 160 | }, |
148 | ast::EnumDef(it) => { | 161 | ast::EnumDef(it) => { |
149 | let def: hir::Enum = sema.to_def(&it)?; | 162 | let def: hir::Enum = sema.to_def(&it)?; |
150 | Some(Definition::ModuleDef(def.into())) | 163 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
151 | }, | 164 | }, |
152 | ast::TraitDef(it) => { | 165 | ast::TraitDef(it) => { |
153 | let def: hir::Trait = sema.to_def(&it)?; | 166 | let def: hir::Trait = sema.to_def(&it)?; |
154 | Some(Definition::ModuleDef(def.into())) | 167 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
155 | }, | 168 | }, |
156 | ast::StaticDef(it) => { | 169 | ast::StaticDef(it) => { |
157 | let def: hir::Static = sema.to_def(&it)?; | 170 | let def: hir::Static = sema.to_def(&it)?; |
158 | Some(Definition::ModuleDef(def.into())) | 171 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
159 | }, | 172 | }, |
160 | ast::EnumVariant(it) => { | 173 | ast::EnumVariant(it) => { |
161 | let def: hir::EnumVariant = sema.to_def(&it)?; | 174 | let def: hir::EnumVariant = sema.to_def(&it)?; |
162 | Some(Definition::ModuleDef(def.into())) | 175 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
163 | }, | 176 | }, |
164 | ast::FnDef(it) => { | 177 | ast::FnDef(it) => { |
165 | let def: hir::Function = sema.to_def(&it)?; | 178 | let def: hir::Function = sema.to_def(&it)?; |
166 | Some(Definition::ModuleDef(def.into())) | 179 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
167 | }, | 180 | }, |
168 | ast::ConstDef(it) => { | 181 | ast::ConstDef(it) => { |
169 | let def: hir::Const = sema.to_def(&it)?; | 182 | let def: hir::Const = sema.to_def(&it)?; |
170 | Some(Definition::ModuleDef(def.into())) | 183 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
171 | }, | 184 | }, |
172 | ast::TypeAliasDef(it) => { | 185 | ast::TypeAliasDef(it) => { |
173 | let def: hir::TypeAlias = sema.to_def(&it)?; | 186 | let def: hir::TypeAlias = sema.to_def(&it)?; |
174 | Some(Definition::ModuleDef(def.into())) | 187 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) |
175 | }, | 188 | }, |
176 | ast::MacroCall(it) => { | 189 | ast::MacroCall(it) => { |
177 | let def = sema.to_def(&it)?; | 190 | let def = sema.to_def(&it)?; |
178 | Some(Definition::Macro(def)) | 191 | Some(NameClass::Definition(Definition::Macro(def))) |
179 | }, | 192 | }, |
180 | ast::TypeParam(it) => { | 193 | ast::TypeParam(it) => { |
181 | let def = sema.to_def(&it)?; | 194 | let def = sema.to_def(&it)?; |
182 | Some(Definition::TypeParam(def)) | 195 | Some(NameClass::Definition(Definition::TypeParam(def))) |
183 | }, | 196 | }, |
184 | _ => None, | 197 | _ => None, |
185 | } | 198 | } |
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index bf0d8db60..fff112e66 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the ra_assists module. | 1 | //! This module contains an import search funcionality that is provided to the ra_assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. |
3 | 3 | ||
4 | use hir::{MacroDef, ModuleDef, Semantics}; | 4 | use hir::{Crate, MacroDef, ModuleDef, Semantics}; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | 6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; |
7 | 7 | ||
@@ -11,44 +11,46 @@ use crate::{ | |||
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use either::Either; | 13 | use either::Either; |
14 | use rustc_hash::FxHashSet; | ||
14 | 15 | ||
15 | pub struct ImportsLocator<'a> { | 16 | pub struct ImportsLocator<'a> { |
16 | sema: Semantics<'a, RootDatabase>, | 17 | sema: Semantics<'a, RootDatabase>, |
18 | krate: Crate, | ||
17 | } | 19 | } |
18 | 20 | ||
19 | impl<'a> ImportsLocator<'a> { | 21 | impl<'a> ImportsLocator<'a> { |
20 | pub fn new(db: &'a RootDatabase) -> Self { | 22 | pub fn new(db: &'a RootDatabase, krate: Crate) -> Self { |
21 | Self { sema: Semantics::new(db) } | 23 | Self { sema: Semantics::new(db), krate } |
22 | } | 24 | } |
23 | 25 | ||
24 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { | 26 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { |
25 | let _p = profile("search_for_imports"); | 27 | let _p = profile("search_for_imports"); |
26 | let db = self.sema.db; | 28 | let db = self.sema.db; |
27 | 29 | ||
28 | let project_results = { | 30 | // Query dependencies first. |
29 | let mut query = Query::new(name_to_import.to_string()); | 31 | let mut candidates: FxHashSet<_> = |
30 | query.exact(); | 32 | self.krate.query_external_importables(db, name_to_import).collect(); |
31 | query.limit(40); | 33 | |
32 | symbol_index::world_symbols(db, query) | 34 | // Query the local crate using the symbol index. |
33 | }; | 35 | let local_results = { |
34 | let lib_results = { | ||
35 | let mut query = Query::new(name_to_import.to_string()); | 36 | let mut query = Query::new(name_to_import.to_string()); |
36 | query.libs(); | ||
37 | query.exact(); | 37 | query.exact(); |
38 | query.limit(40); | 38 | query.limit(40); |
39 | symbol_index::world_symbols(db, query) | 39 | symbol_index::crate_symbols(db, self.krate.into(), query) |
40 | }; | 40 | }; |
41 | 41 | ||
42 | project_results | 42 | candidates.extend( |
43 | .into_iter() | 43 | local_results |
44 | .chain(lib_results.into_iter()) | 44 | .into_iter() |
45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) | 45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) |
46 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 46 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), | 47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), |
48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), | 48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), |
49 | _ => None, | 49 | _ => None, |
50 | }) | 50 | }), |
51 | .collect() | 51 | ); |
52 | |||
53 | candidates.into_iter().collect() | ||
52 | } | 54 | } |
53 | 55 | ||
54 | fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { | 56 | fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 1b74e6558..a808de4f1 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -16,10 +16,10 @@ use std::sync::Arc; | |||
16 | use hir::db::{AstDatabase, DefDatabase}; | 16 | use hir::db::{AstDatabase, DefDatabase}; |
17 | use ra_db::{ | 17 | use ra_db::{ |
18 | salsa::{self, Database, Durability}, | 18 | salsa::{self, Database, Durability}, |
19 | Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, | 19 | Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, |
20 | SourceDatabase, SourceRootId, Upcast, | 20 | Upcast, |
21 | }; | 21 | }; |
22 | use rustc_hash::FxHashMap; | 22 | use rustc_hash::FxHashSet; |
23 | 23 | ||
24 | use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; | 24 | use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; |
25 | 25 | ||
@@ -36,7 +36,6 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; | |||
36 | #[derive(Debug)] | 36 | #[derive(Debug)] |
37 | pub struct RootDatabase { | 37 | pub struct RootDatabase { |
38 | runtime: salsa::Runtime<RootDatabase>, | 38 | runtime: salsa::Runtime<RootDatabase>, |
39 | pub(crate) debug_data: Arc<DebugData>, | ||
40 | pub last_gc: crate::wasm_shims::Instant, | 39 | pub last_gc: crate::wasm_shims::Instant, |
41 | pub last_gc_check: crate::wasm_shims::Instant, | 40 | pub last_gc_check: crate::wasm_shims::Instant, |
42 | } | 41 | } |
@@ -57,23 +56,12 @@ impl FileLoader for RootDatabase { | |||
57 | fn file_text(&self, file_id: FileId) -> Arc<String> { | 56 | fn file_text(&self, file_id: FileId) -> Arc<String> { |
58 | FileLoaderDelegate(self).file_text(file_id) | 57 | FileLoaderDelegate(self).file_text(file_id) |
59 | } | 58 | } |
60 | fn resolve_relative_path( | 59 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
61 | &self, | 60 | FileLoaderDelegate(self).resolve_path(anchor, path) |
62 | anchor: FileId, | ||
63 | relative_path: &RelativePath, | ||
64 | ) -> Option<FileId> { | ||
65 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
66 | } | 61 | } |
67 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 62 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
68 | FileLoaderDelegate(self).relevant_crates(file_id) | 63 | FileLoaderDelegate(self).relevant_crates(file_id) |
69 | } | 64 | } |
70 | fn resolve_extern_path( | ||
71 | &self, | ||
72 | extern_id: ra_db::ExternSourceId, | ||
73 | relative_path: &RelativePath, | ||
74 | ) -> Option<FileId> { | ||
75 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
76 | } | ||
77 | } | 65 | } |
78 | 66 | ||
79 | impl salsa::Database for RootDatabase { | 67 | impl salsa::Database for RootDatabase { |
@@ -109,7 +97,6 @@ impl RootDatabase { | |||
109 | runtime: salsa::Runtime::default(), | 97 | runtime: salsa::Runtime::default(), |
110 | last_gc: crate::wasm_shims::Instant::now(), | 98 | last_gc: crate::wasm_shims::Instant::now(), |
111 | last_gc_check: crate::wasm_shims::Instant::now(), | 99 | last_gc_check: crate::wasm_shims::Instant::now(), |
112 | debug_data: Default::default(), | ||
113 | }; | 100 | }; |
114 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); | 101 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); |
115 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); | 102 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); |
@@ -132,7 +119,6 @@ impl salsa::ParallelDatabase for RootDatabase { | |||
132 | runtime: self.runtime.snapshot(self), | 119 | runtime: self.runtime.snapshot(self), |
133 | last_gc: self.last_gc, | 120 | last_gc: self.last_gc, |
134 | last_gc_check: self.last_gc_check, | 121 | last_gc_check: self.last_gc_check, |
135 | debug_data: Arc::clone(&self.debug_data), | ||
136 | }) | 122 | }) |
137 | } | 123 | } |
138 | } | 124 | } |
@@ -146,14 +132,3 @@ fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> { | |||
146 | let text = db.file_text(file_id); | 132 | let text = db.file_text(file_id); |
147 | Arc::new(LineIndex::new(&*text)) | 133 | Arc::new(LineIndex::new(&*text)) |
148 | } | 134 | } |
149 | |||
150 | #[derive(Debug, Default, Clone)] | ||
151 | pub(crate) struct DebugData { | ||
152 | pub(crate) root_paths: FxHashMap<SourceRootId, String>, | ||
153 | } | ||
154 | |||
155 | impl DebugData { | ||
156 | pub(crate) fn merge(&mut self, other: DebugData) { | ||
157 | self.root_paths.extend(other.root_paths.into_iter()); | ||
158 | } | ||
159 | } | ||
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs index e713f4b7e..f40ae8304 100644 --- a/crates/ra_ide_db/src/source_change.rs +++ b/crates/ra_ide_db/src/source_change.rs | |||
@@ -22,17 +22,6 @@ impl SourceChange { | |||
22 | ) -> Self { | 22 | ) -> Self { |
23 | SourceChange { source_file_edits, file_system_edits, is_snippet: false } | 23 | SourceChange { source_file_edits, file_system_edits, is_snippet: false } |
24 | } | 24 | } |
25 | |||
26 | /// Creates a new SourceChange with the given label, | ||
27 | /// containing only the given `SourceFileEdits`. | ||
28 | pub fn source_file_edits(edits: Vec<SourceFileEdit>) -> Self { | ||
29 | SourceChange { source_file_edits: edits, file_system_edits: vec![], is_snippet: false } | ||
30 | } | ||
31 | /// Creates a new SourceChange with the given label | ||
32 | /// from the given `FileId` and `TextEdit` | ||
33 | pub fn source_file_edit_from(file_id: FileId, edit: TextEdit) -> Self { | ||
34 | SourceFileEdit { file_id, edit }.into() | ||
35 | } | ||
36 | } | 25 | } |
37 | 26 | ||
38 | #[derive(Debug, Clone)] | 27 | #[derive(Debug, Clone)] |
@@ -43,11 +32,13 @@ pub struct SourceFileEdit { | |||
43 | 32 | ||
44 | impl From<SourceFileEdit> for SourceChange { | 33 | impl From<SourceFileEdit> for SourceChange { |
45 | fn from(edit: SourceFileEdit) -> SourceChange { | 34 | fn from(edit: SourceFileEdit) -> SourceChange { |
46 | SourceChange { | 35 | vec![edit].into() |
47 | source_file_edits: vec![edit], | 36 | } |
48 | file_system_edits: Vec::new(), | 37 | } |
49 | is_snippet: false, | 38 | |
50 | } | 39 | impl From<Vec<SourceFileEdit>> for SourceChange { |
40 | fn from(source_file_edits: Vec<SourceFileEdit>) -> SourceChange { | ||
41 | SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } | ||
51 | } | 42 | } |
52 | } | 43 | } |
53 | 44 | ||
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index acc31fe3b..aab918973 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs | |||
@@ -29,9 +29,10 @@ use std::{ | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | use fst::{self, Streamer}; | 31 | use fst::{self, Streamer}; |
32 | use hir::db::DefDatabase; | ||
32 | use ra_db::{ | 33 | use ra_db::{ |
33 | salsa::{self, ParallelDatabase}, | 34 | salsa::{self, ParallelDatabase}, |
34 | FileId, SourceDatabaseExt, SourceRootId, | 35 | CrateId, FileId, SourceDatabaseExt, SourceRootId, |
35 | }; | 36 | }; |
36 | use ra_syntax::{ | 37 | use ra_syntax::{ |
37 | ast::{self, NameOwner}, | 38 | ast::{self, NameOwner}, |
@@ -110,6 +111,14 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> | |||
110 | Arc::new(SymbolIndex::new(symbols)) | 111 | Arc::new(SymbolIndex::new(symbols)) |
111 | } | 112 | } |
112 | 113 | ||
114 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | ||
115 | struct Snap(salsa::Snapshot<RootDatabase>); | ||
116 | impl Clone for Snap { | ||
117 | fn clone(&self) -> Snap { | ||
118 | Snap(self.0.snapshot()) | ||
119 | } | ||
120 | } | ||
121 | |||
113 | // Feature: Workspace Symbol | 122 | // Feature: Workspace Symbol |
114 | // | 123 | // |
115 | // Uses fuzzy-search to find types, modules and functions by name across your | 124 | // Uses fuzzy-search to find types, modules and functions by name across your |
@@ -132,13 +141,7 @@ fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> | |||
132 | // | VS Code | kbd:[Ctrl+T] | 141 | // | VS Code | kbd:[Ctrl+T] |
133 | // |=== | 142 | // |=== |
134 | pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { | 143 | pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { |
135 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | 144 | let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone()); |
136 | struct Snap(salsa::Snapshot<RootDatabase>); | ||
137 | impl Clone for Snap { | ||
138 | fn clone(&self) -> Snap { | ||
139 | Snap(self.0.snapshot()) | ||
140 | } | ||
141 | } | ||
142 | 145 | ||
143 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { | 146 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { |
144 | let snap = Snap(db.snapshot()); | 147 | let snap = Snap(db.snapshot()); |
@@ -173,6 +176,33 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { | |||
173 | query.search(&buf) | 176 | query.search(&buf) |
174 | } | 177 | } |
175 | 178 | ||
179 | pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> { | ||
180 | // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from | ||
181 | // that instead? | ||
182 | |||
183 | let def_map = db.crate_def_map(krate); | ||
184 | let mut files = Vec::new(); | ||
185 | let mut modules = vec![def_map.root]; | ||
186 | while let Some(module) = modules.pop() { | ||
187 | let data = &def_map[module]; | ||
188 | files.extend(data.origin.file_id()); | ||
189 | modules.extend(data.children.values()); | ||
190 | } | ||
191 | |||
192 | let snap = Snap(db.snapshot()); | ||
193 | |||
194 | #[cfg(not(feature = "wasm"))] | ||
195 | let buf = files | ||
196 | .par_iter() | ||
197 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) | ||
198 | .collect::<Vec<_>>(); | ||
199 | |||
200 | #[cfg(feature = "wasm")] | ||
201 | let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect::<Vec<_>>(); | ||
202 | |||
203 | query.search(&buf) | ||
204 | } | ||
205 | |||
176 | pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { | 206 | pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> { |
177 | let name = name_ref.text(); | 207 | let name = name_ref.text(); |
178 | let mut query = Query::new(name.to_string()); | 208 | let mut query = Query::new(name.to_string()); |
@@ -298,9 +328,6 @@ impl Query { | |||
298 | let mut stream = op.union(); | 328 | let mut stream = op.union(); |
299 | let mut res = Vec::new(); | 329 | let mut res = Vec::new(); |
300 | while let Some((_, indexed_values)) = stream.next() { | 330 | while let Some((_, indexed_values)) = stream.next() { |
301 | if res.len() >= self.limit { | ||
302 | break; | ||
303 | } | ||
304 | for indexed_value in indexed_values { | 331 | for indexed_value in indexed_values { |
305 | let symbol_index = &indices[indexed_value.index]; | 332 | let symbol_index = &indices[indexed_value.index]; |
306 | let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); | 333 | let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value); |
@@ -312,7 +339,11 @@ impl Query { | |||
312 | if self.exact && symbol.name != self.query { | 339 | if self.exact && symbol.name != self.query { |
313 | continue; | 340 | continue; |
314 | } | 341 | } |
342 | |||
315 | res.push(symbol.clone()); | 343 | res.push(symbol.clone()); |
344 | if res.len() >= self.limit { | ||
345 | return res; | ||
346 | } | ||
316 | } | 347 | } |
317 | } | 348 | } |
318 | } | 349 | } |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index be0cd5661..293baecf6 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -18,9 +18,10 @@ | |||
18 | //! // fn foo() {} | 18 | //! // fn foo() {} |
19 | //! ``` | 19 | //! ``` |
20 | //! | 20 | //! |
21 | //! After adding a new inline-test, run `cargo collect-tests` to extract | 21 | //! After adding a new inline-test, run `cargo xtask codegen` to |
22 | //! it as a standalone text-fixture into `tests/data/parser/inline`, and | 22 | //! extract it as a standalone text-fixture into |
23 | //! run `cargo test` once to create the "gold" value. | 23 | //! `crates/ra_syntax/test_data/parser/`, and run `cargo test` once to |
24 | //! create the "gold" value. | ||
24 | //! | 25 | //! |
25 | //! Coding convention: rules like `where_clause` always produce either a | 26 | //! Coding convention: rules like `where_clause` always produce either a |
26 | //! node or an error, rules like `opt_where_clause` may produce nothing. | 27 | //! node or an error, rules like `opt_where_clause` may produce nothing. |
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 67a924de5..97642bc24 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs | |||
@@ -118,7 +118,22 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
118 | && p.at_contextual_kw("default") | 118 | && p.at_contextual_kw("default") |
119 | && (match p.nth(1) { | 119 | && (match p.nth(1) { |
120 | T![impl] => true, | 120 | T![impl] => true, |
121 | T![fn] | T![type] => { | 121 | T![unsafe] => { |
122 | // test default_unsafe_impl | ||
123 | // default unsafe impl Foo {} | ||
124 | |||
125 | // test default_unsafe_fn | ||
126 | // impl T for Foo { | ||
127 | // default unsafe fn foo() {} | ||
128 | // } | ||
129 | if p.nth(2) == T![impl] || p.nth(2) == T![fn] { | ||
130 | p.bump_remap(T![default]); | ||
131 | p.bump(T![unsafe]); | ||
132 | has_mods = true; | ||
133 | } | ||
134 | false | ||
135 | } | ||
136 | T![fn] | T![type] | T![const] => { | ||
122 | if let ItemFlavor::Mod = flavor { | 137 | if let ItemFlavor::Mod = flavor { |
123 | true | 138 | true |
124 | } else { | 139 | } else { |
@@ -198,6 +213,9 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
198 | // default type T = Bar; | 213 | // default type T = Bar; |
199 | // default fn foo() {} | 214 | // default fn foo() {} |
200 | // } | 215 | // } |
216 | T![const] => { | ||
217 | consts::const_def(p, m); | ||
218 | } | ||
201 | 219 | ||
202 | // test unsafe_default_impl | 220 | // test unsafe_default_impl |
203 | // unsafe default impl Foo {} | 221 | // unsafe default impl Foo {} |
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs index 332acc1a0..428aa711e 100644 --- a/crates/ra_parser/src/grammar/paths.rs +++ b/crates/ra_parser/src/grammar/paths.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use super::*; | 3 | use super::*; |
4 | 4 | ||
5 | pub(super) const PATH_FIRST: TokenSet = | 5 | pub(super) const PATH_FIRST: TokenSet = |
6 | token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLON, L_ANGLE]; | 6 | token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]]; |
7 | 7 | ||
8 | pub(super) fn is_path_start(p: &Parser) -> bool { | 8 | pub(super) fn is_path_start(p: &Parser) -> bool { |
9 | is_use_path_start(p) || p.at(T![<]) | 9 | is_use_path_start(p) || p.at(T![<]) |
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 68fb2fc73..427c0eb49 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs | |||
@@ -4,7 +4,7 @@ use super::*; | |||
4 | 4 | ||
5 | pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST | 5 | pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST |
6 | .union(paths::PATH_FIRST) | 6 | .union(paths::PATH_FIRST) |
7 | .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]); | 7 | .union(token_set![T![box], T![ref], T![mut], T!['('], T!['['], T![&], T![_], T![-], T![.]]); |
8 | 8 | ||
9 | pub(crate) fn pattern(p: &mut Parser) { | 9 | pub(crate) fn pattern(p: &mut Parser) { |
10 | pattern_r(p, PAT_RECOVERY_SET); | 10 | pattern_r(p, PAT_RECOVERY_SET); |
@@ -88,7 +88,9 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | |||
88 | _ => bind_pat(p, true), | 88 | _ => bind_pat(p, true), |
89 | }, | 89 | }, |
90 | 90 | ||
91 | _ if paths::is_use_path_start(p) => path_or_macro_pat(p), | 91 | // test type_path_in_pattern |
92 | // fn main() { let <_>::Foo = (); } | ||
93 | _ if paths::is_path_start(p) => path_or_macro_pat(p), | ||
92 | _ if is_literal_pat_start(p) => literal_pat(p), | 94 | _ if is_literal_pat_start(p) => literal_pat(p), |
93 | 95 | ||
94 | T![.] if p.at(T![..]) => dot_dot_pat(p), | 96 | T![.] if p.at(T![..]) => dot_dot_pat(p), |
@@ -138,7 +140,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker { | |||
138 | // let Bar(..) = (); | 140 | // let Bar(..) = (); |
139 | // } | 141 | // } |
140 | fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker { | 142 | fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker { |
141 | assert!(paths::is_use_path_start(p)); | 143 | assert!(paths::is_path_start(p)); |
142 | let m = p.start(); | 144 | let m = p.start(); |
143 | paths::expr_path(p); | 145 | paths::expr_path(p); |
144 | let kind = match p.current() { | 146 | let kind = match p.current() { |
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index 50e4900c3..325d566ad 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs | |||
@@ -191,10 +191,14 @@ fn where_predicate(p: &mut Parser) { | |||
191 | } | 191 | } |
192 | _ => { | 192 | _ => { |
193 | // test where_pred_for | 193 | // test where_pred_for |
194 | // fn test<F>() | 194 | // fn for_trait<F>() |
195 | // where | 195 | // where |
196 | // for<'a> F: Fn(&'a str) | 196 | // for<'a> F: Fn(&'a str) |
197 | // { } | 197 | // { } |
198 | if p.at(T![for]) { | ||
199 | types::for_binder(p); | ||
200 | } | ||
201 | |||
198 | types::type_(p); | 202 | types::type_(p); |
199 | 203 | ||
200 | if p.at(T![:]) { | 204 | if p.at(T![:]) { |
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index fe1a039cb..9e8e3bd97 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs | |||
@@ -216,19 +216,21 @@ pub(super) fn for_binder(p: &mut Parser) { | |||
216 | 216 | ||
217 | // test for_type | 217 | // test for_type |
218 | // type A = for<'a> fn() -> (); | 218 | // type A = for<'a> fn() -> (); |
219 | // fn foo<T>(_t: &T) where for<'a> &'a T: Iterator {} | 219 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); |
220 | // fn bar<T>(_t: &T) where for<'a> &'a mut T: Iterator {} | 220 | // type Obj = for<'a> PartialEq<&'a i32>; |
221 | // fn baz<T>(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {} | ||
222 | pub(super) fn for_type(p: &mut Parser) { | 221 | pub(super) fn for_type(p: &mut Parser) { |
223 | assert!(p.at(T![for])); | 222 | assert!(p.at(T![for])); |
224 | let m = p.start(); | 223 | let m = p.start(); |
225 | for_binder(p); | 224 | for_binder(p); |
226 | match p.current() { | 225 | match p.current() { |
227 | T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), | 226 | T![fn] | T![unsafe] | T![extern] => {} |
228 | T![&] => reference_type(p), | 227 | // OK: legacy trait object format |
229 | _ if paths::is_path_start(p) => path_type_(p, false), | 228 | _ if paths::is_use_path_start(p) => {} |
230 | _ => p.error("expected a path"), | 229 | _ => { |
230 | p.error("expected a function pointer or path"); | ||
231 | } | ||
231 | } | 232 | } |
233 | type_no_bounds(p); | ||
232 | m.complete(p, FOR_TYPE); | 234 | m.complete(p, FOR_TYPE); |
233 | } | 235 | } |
234 | 236 | ||
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index bb3003278..582102945 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml | |||
@@ -22,3 +22,4 @@ cargo_metadata = "0.10.0" | |||
22 | difference = "2.0.0" | 22 | difference = "2.0.0" |
23 | # used as proc macro test target | 23 | # used as proc macro test target |
24 | serde_derive = "1.0.106" | 24 | serde_derive = "1.0.106" |
25 | ra_toolchain = { path = "../ra_toolchain" } | ||
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs index 84348b5de..8d85f2d8a 100644 --- a/crates/ra_proc_macro_srv/src/tests/utils.rs +++ b/crates/ra_proc_macro_srv/src/tests/utils.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | use crate::dylib; | 3 | use crate::dylib; |
4 | use crate::ProcMacroSrv; | 4 | use crate::ProcMacroSrv; |
5 | pub use difference::Changeset as __Changeset; | ||
6 | use ra_proc_macro::ListMacrosTask; | 5 | use ra_proc_macro::ListMacrosTask; |
7 | use std::str::FromStr; | 6 | use std::str::FromStr; |
8 | use test_utils::assert_eq_text; | 7 | use test_utils::assert_eq_text; |
@@ -13,7 +12,7 @@ mod fixtures { | |||
13 | 12 | ||
14 | // Use current project metadata to get the proc-macro dylib path | 13 | // Use current project metadata to get the proc-macro dylib path |
15 | pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { | 14 | pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { |
16 | let command = Command::new("cargo") | 15 | let command = Command::new(ra_toolchain::cargo()) |
17 | .args(&["check", "--message-format", "json"]) | 16 | .args(&["check", "--message-format", "json"]) |
18 | .output() | 17 | .output() |
19 | .unwrap() | 18 | .unwrap() |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index a306ce95f..4b7444039 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -64,7 +64,7 @@ impl Default for CargoConfig { | |||
64 | fn default() -> Self { | 64 | fn default() -> Self { |
65 | CargoConfig { | 65 | CargoConfig { |
66 | no_default_features: false, | 66 | no_default_features: false, |
67 | all_features: true, | 67 | all_features: false, |
68 | features: Vec::new(), | 68 | features: Vec::new(), |
69 | load_out_dirs_from_check: false, | 69 | load_out_dirs_from_check: false, |
70 | target: None, | 70 | target: None, |
diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs index b030c8a6a..ee2de4c25 100644 --- a/crates/ra_project_model/src/json_project.rs +++ b/crates/ra_project_model/src/json_project.rs | |||
@@ -2,9 +2,16 @@ | |||
2 | 2 | ||
3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
4 | 4 | ||
5 | use rustc_hash::{FxHashMap, FxHashSet}; | 5 | use rustc_hash::FxHashSet; |
6 | use serde::Deserialize; | 6 | use serde::Deserialize; |
7 | 7 | ||
8 | /// Roots and crates that compose this Rust project. | ||
9 | #[derive(Clone, Debug, Deserialize)] | ||
10 | pub struct JsonProject { | ||
11 | pub(crate) roots: Vec<Root>, | ||
12 | pub(crate) crates: Vec<Crate>, | ||
13 | } | ||
14 | |||
8 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in | 15 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in |
9 | /// all roots. Roots might be nested. | 16 | /// all roots. Roots might be nested. |
10 | #[derive(Clone, Debug, Deserialize)] | 17 | #[derive(Clone, Debug, Deserialize)] |
@@ -20,8 +27,10 @@ pub struct Crate { | |||
20 | pub(crate) root_module: PathBuf, | 27 | pub(crate) root_module: PathBuf, |
21 | pub(crate) edition: Edition, | 28 | pub(crate) edition: Edition, |
22 | pub(crate) deps: Vec<Dep>, | 29 | pub(crate) deps: Vec<Dep>, |
23 | pub(crate) atom_cfgs: FxHashSet<String>, | 30 | |
24 | pub(crate) key_value_cfgs: FxHashMap<String, String>, | 31 | #[serde(default)] |
32 | pub(crate) cfg: FxHashSet<String>, | ||
33 | |||
25 | pub(crate) out_dir: Option<PathBuf>, | 34 | pub(crate) out_dir: Option<PathBuf>, |
26 | pub(crate) proc_macro_dylib_path: Option<PathBuf>, | 35 | pub(crate) proc_macro_dylib_path: Option<PathBuf>, |
27 | } | 36 | } |
@@ -48,9 +57,39 @@ pub struct Dep { | |||
48 | pub(crate) name: String, | 57 | pub(crate) name: String, |
49 | } | 58 | } |
50 | 59 | ||
51 | /// Roots and crates that compose this Rust project. | 60 | #[cfg(test)] |
52 | #[derive(Clone, Debug, Deserialize)] | 61 | mod tests { |
53 | pub struct JsonProject { | 62 | use super::*; |
54 | pub(crate) roots: Vec<Root>, | 63 | use serde_json::json; |
55 | pub(crate) crates: Vec<Crate>, | 64 | |
65 | #[test] | ||
66 | fn test_crate_deserialization() { | ||
67 | let raw_json = json!( { | ||
68 | "crate_id": 2, | ||
69 | "root_module": "this/is/a/file/path.rs", | ||
70 | "deps": [ | ||
71 | { | ||
72 | "crate": 1, | ||
73 | "name": "some_dep_crate" | ||
74 | }, | ||
75 | ], | ||
76 | "edition": "2015", | ||
77 | "cfg": [ | ||
78 | "atom_1", | ||
79 | "atom_2", | ||
80 | "feature=feature_1", | ||
81 | "feature=feature_2", | ||
82 | "other=value", | ||
83 | ], | ||
84 | |||
85 | }); | ||
86 | |||
87 | let krate: Crate = serde_json::from_value(raw_json).unwrap(); | ||
88 | |||
89 | assert!(krate.cfg.contains(&"atom_1".to_string())); | ||
90 | assert!(krate.cfg.contains(&"atom_2".to_string())); | ||
91 | assert!(krate.cfg.contains(&"feature=feature_1".to_string())); | ||
92 | assert!(krate.cfg.contains(&"feature=feature_2".to_string())); | ||
93 | assert!(krate.cfg.contains(&"other=value".to_string())); | ||
94 | } | ||
56 | } | 95 | } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index a2e9f65ef..cb0e27dce 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -14,7 +14,7 @@ use std::{ | |||
14 | use anyhow::{bail, Context, Result}; | 14 | use anyhow::{bail, Context, Result}; |
15 | use ra_cfg::CfgOptions; | 15 | use ra_cfg::CfgOptions; |
16 | use ra_db::{CrateGraph, CrateName, Edition, Env, ExternSource, ExternSourceId, FileId}; | 16 | use ra_db::{CrateGraph, CrateName, Edition, Env, ExternSource, ExternSourceId, FileId}; |
17 | use rustc_hash::FxHashMap; | 17 | use rustc_hash::{FxHashMap, FxHashSet}; |
18 | use serde_json::from_reader; | 18 | use serde_json::from_reader; |
19 | 19 | ||
20 | pub use crate::{ | 20 | pub use crate::{ |
@@ -32,6 +32,12 @@ pub enum ProjectWorkspace { | |||
32 | Json { project: JsonProject }, | 32 | Json { project: JsonProject }, |
33 | } | 33 | } |
34 | 34 | ||
35 | impl From<JsonProject> for ProjectWorkspace { | ||
36 | fn from(project: JsonProject) -> ProjectWorkspace { | ||
37 | ProjectWorkspace::Json { project } | ||
38 | } | ||
39 | } | ||
40 | |||
35 | /// `PackageRoot` describes a package root folder. | 41 | /// `PackageRoot` describes a package root folder. |
36 | /// Which may be an external dependency, or a member of | 42 | /// Which may be an external dependency, or a member of |
37 | /// the current workspace. | 43 | /// the current workspace. |
@@ -41,41 +47,45 @@ pub struct PackageRoot { | |||
41 | path: PathBuf, | 47 | path: PathBuf, |
42 | /// Is a member of the current workspace | 48 | /// Is a member of the current workspace |
43 | is_member: bool, | 49 | is_member: bool, |
50 | out_dir: Option<PathBuf>, | ||
44 | } | 51 | } |
45 | impl PackageRoot { | 52 | impl PackageRoot { |
46 | pub fn new_member(path: PathBuf) -> PackageRoot { | 53 | pub fn new_member(path: PathBuf) -> PackageRoot { |
47 | Self { path, is_member: true } | 54 | Self { path, is_member: true, out_dir: None } |
48 | } | 55 | } |
49 | pub fn new_non_member(path: PathBuf) -> PackageRoot { | 56 | pub fn new_non_member(path: PathBuf) -> PackageRoot { |
50 | Self { path, is_member: false } | 57 | Self { path, is_member: false, out_dir: None } |
51 | } | 58 | } |
52 | pub fn path(&self) -> &Path { | 59 | pub fn path(&self) -> &Path { |
53 | &self.path | 60 | &self.path |
54 | } | 61 | } |
62 | pub fn out_dir(&self) -> Option<&Path> { | ||
63 | self.out_dir.as_deref() | ||
64 | } | ||
55 | pub fn is_member(&self) -> bool { | 65 | pub fn is_member(&self) -> bool { |
56 | self.is_member | 66 | self.is_member |
57 | } | 67 | } |
58 | } | 68 | } |
59 | 69 | ||
60 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 70 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] |
61 | pub enum ProjectRoot { | 71 | pub enum ProjectManifest { |
62 | ProjectJson(PathBuf), | 72 | ProjectJson(PathBuf), |
63 | CargoToml(PathBuf), | 73 | CargoToml(PathBuf), |
64 | } | 74 | } |
65 | 75 | ||
66 | impl ProjectRoot { | 76 | impl ProjectManifest { |
67 | pub fn from_manifest_file(path: PathBuf) -> Result<ProjectRoot> { | 77 | pub fn from_manifest_file(path: PathBuf) -> Result<ProjectManifest> { |
68 | if path.ends_with("rust-project.json") { | 78 | if path.ends_with("rust-project.json") { |
69 | return Ok(ProjectRoot::ProjectJson(path)); | 79 | return Ok(ProjectManifest::ProjectJson(path)); |
70 | } | 80 | } |
71 | if path.ends_with("Cargo.toml") { | 81 | if path.ends_with("Cargo.toml") { |
72 | return Ok(ProjectRoot::CargoToml(path)); | 82 | return Ok(ProjectManifest::CargoToml(path)); |
73 | } | 83 | } |
74 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) | 84 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) |
75 | } | 85 | } |
76 | 86 | ||
77 | pub fn discover_single(path: &Path) -> Result<ProjectRoot> { | 87 | pub fn discover_single(path: &Path) -> Result<ProjectManifest> { |
78 | let mut candidates = ProjectRoot::discover(path)?; | 88 | let mut candidates = ProjectManifest::discover(path)?; |
79 | let res = match candidates.pop() { | 89 | let res = match candidates.pop() { |
80 | None => bail!("no projects"), | 90 | None => bail!("no projects"), |
81 | Some(it) => it, | 91 | Some(it) => it, |
@@ -87,12 +97,12 @@ impl ProjectRoot { | |||
87 | Ok(res) | 97 | Ok(res) |
88 | } | 98 | } |
89 | 99 | ||
90 | pub fn discover(path: &Path) -> io::Result<Vec<ProjectRoot>> { | 100 | pub fn discover(path: &Path) -> io::Result<Vec<ProjectManifest>> { |
91 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { | 101 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { |
92 | return Ok(vec![ProjectRoot::ProjectJson(project_json)]); | 102 | return Ok(vec![ProjectManifest::ProjectJson(project_json)]); |
93 | } | 103 | } |
94 | return find_cargo_toml(path) | 104 | return find_cargo_toml(path) |
95 | .map(|paths| paths.into_iter().map(ProjectRoot::CargoToml).collect()); | 105 | .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); |
96 | 106 | ||
97 | fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> { | 107 | fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> { |
98 | match find_in_parent_dirs(path, "Cargo.toml") { | 108 | match find_in_parent_dirs(path, "Cargo.toml") { |
@@ -128,16 +138,28 @@ impl ProjectRoot { | |||
128 | .collect() | 138 | .collect() |
129 | } | 139 | } |
130 | } | 140 | } |
141 | |||
142 | pub fn discover_all(paths: &[impl AsRef<Path>]) -> Vec<ProjectManifest> { | ||
143 | let mut res = paths | ||
144 | .iter() | ||
145 | .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) | ||
146 | .flatten() | ||
147 | .collect::<FxHashSet<_>>() | ||
148 | .into_iter() | ||
149 | .collect::<Vec<_>>(); | ||
150 | res.sort(); | ||
151 | res | ||
152 | } | ||
131 | } | 153 | } |
132 | 154 | ||
133 | impl ProjectWorkspace { | 155 | impl ProjectWorkspace { |
134 | pub fn load( | 156 | pub fn load( |
135 | root: ProjectRoot, | 157 | manifest: ProjectManifest, |
136 | cargo_features: &CargoConfig, | 158 | cargo_features: &CargoConfig, |
137 | with_sysroot: bool, | 159 | with_sysroot: bool, |
138 | ) -> Result<ProjectWorkspace> { | 160 | ) -> Result<ProjectWorkspace> { |
139 | let res = match root { | 161 | let res = match manifest { |
140 | ProjectRoot::ProjectJson(project_json) => { | 162 | ProjectManifest::ProjectJson(project_json) => { |
141 | let file = File::open(&project_json).with_context(|| { | 163 | let file = File::open(&project_json).with_context(|| { |
142 | format!("Failed to open json file {}", project_json.display()) | 164 | format!("Failed to open json file {}", project_json.display()) |
143 | })?; | 165 | })?; |
@@ -148,7 +170,7 @@ impl ProjectWorkspace { | |||
148 | })?, | 170 | })?, |
149 | } | 171 | } |
150 | } | 172 | } |
151 | ProjectRoot::CargoToml(cargo_toml) => { | 173 | ProjectManifest::CargoToml(cargo_toml) => { |
152 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) | 174 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) |
153 | .with_context(|| { | 175 | .with_context(|| { |
154 | format!( | 176 | format!( |
@@ -186,6 +208,7 @@ impl ProjectWorkspace { | |||
186 | .map(|pkg| PackageRoot { | 208 | .map(|pkg| PackageRoot { |
187 | path: cargo[pkg].root().to_path_buf(), | 209 | path: cargo[pkg].root().to_path_buf(), |
188 | is_member: cargo[pkg].is_member, | 210 | is_member: cargo[pkg].is_member, |
211 | out_dir: cargo[pkg].out_dir.clone(), | ||
189 | }) | 212 | }) |
190 | .chain(sysroot.crates().map(|krate| { | 213 | .chain(sysroot.crates().map(|krate| { |
191 | PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) | 214 | PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) |
@@ -194,17 +217,6 @@ impl ProjectWorkspace { | |||
194 | } | 217 | } |
195 | } | 218 | } |
196 | 219 | ||
197 | pub fn out_dirs(&self) -> Vec<PathBuf> { | ||
198 | match self { | ||
199 | ProjectWorkspace::Json { project } => { | ||
200 | project.crates.iter().filter_map(|krate| krate.out_dir.as_ref()).cloned().collect() | ||
201 | } | ||
202 | ProjectWorkspace::Cargo { cargo, sysroot: _ } => { | ||
203 | cargo.packages().filter_map(|pkg| cargo[pkg].out_dir.as_ref()).cloned().collect() | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { | 220 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { |
209 | match self { | 221 | match self { |
210 | ProjectWorkspace::Json { project } => project | 222 | ProjectWorkspace::Json { project } => project |
@@ -232,7 +244,7 @@ impl ProjectWorkspace { | |||
232 | 244 | ||
233 | pub fn to_crate_graph( | 245 | pub fn to_crate_graph( |
234 | &self, | 246 | &self, |
235 | default_cfg_options: &CfgOptions, | 247 | target: Option<&str>, |
236 | extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>, | 248 | extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>, |
237 | proc_macro_client: &ProcMacroClient, | 249 | proc_macro_client: &ProcMacroClient, |
238 | load: &mut dyn FnMut(&Path) -> Option<FileId>, | 250 | load: &mut dyn FnMut(&Path) -> Option<FileId>, |
@@ -251,12 +263,16 @@ impl ProjectWorkspace { | |||
251 | json_project::Edition::Edition2018 => Edition::Edition2018, | 263 | json_project::Edition::Edition2018 => Edition::Edition2018, |
252 | }; | 264 | }; |
253 | let cfg_options = { | 265 | let cfg_options = { |
254 | let mut opts = default_cfg_options.clone(); | 266 | let mut opts = CfgOptions::default(); |
255 | for name in &krate.atom_cfgs { | 267 | for cfg in &krate.cfg { |
256 | opts.insert_atom(name.into()); | 268 | match cfg.find('=') { |
257 | } | 269 | None => opts.insert_atom(cfg.into()), |
258 | for (key, value) in &krate.key_value_cfgs { | 270 | Some(pos) => { |
259 | opts.insert_key_value(key.into(), value.into()); | 271 | let key = &cfg[..pos]; |
272 | let value = cfg[pos + 1..].trim_matches('"'); | ||
273 | opts.insert_key_value(key.into(), value.into()); | ||
274 | } | ||
275 | } | ||
260 | } | 276 | } |
261 | opts | 277 | opts |
262 | }; | 278 | }; |
@@ -315,18 +331,13 @@ impl ProjectWorkspace { | |||
315 | } | 331 | } |
316 | } | 332 | } |
317 | ProjectWorkspace::Cargo { cargo, sysroot } => { | 333 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
334 | let mut cfg_options = get_rustc_cfg_options(target); | ||
335 | |||
318 | let sysroot_crates: FxHashMap<_, _> = sysroot | 336 | let sysroot_crates: FxHashMap<_, _> = sysroot |
319 | .crates() | 337 | .crates() |
320 | .filter_map(|krate| { | 338 | .filter_map(|krate| { |
321 | let file_id = load(&sysroot[krate].root)?; | 339 | let file_id = load(&sysroot[krate].root)?; |
322 | 340 | ||
323 | // Crates from sysroot have `cfg(test)` disabled | ||
324 | let cfg_options = { | ||
325 | let mut opts = default_cfg_options.clone(); | ||
326 | opts.remove_atom("test"); | ||
327 | opts | ||
328 | }; | ||
329 | |||
330 | let env = Env::default(); | 341 | let env = Env::default(); |
331 | let extern_source = ExternSource::default(); | 342 | let extern_source = ExternSource::default(); |
332 | let proc_macro = vec![]; | 343 | let proc_macro = vec![]; |
@@ -337,7 +348,7 @@ impl ProjectWorkspace { | |||
337 | file_id, | 348 | file_id, |
338 | Edition::Edition2018, | 349 | Edition::Edition2018, |
339 | Some(crate_name), | 350 | Some(crate_name), |
340 | cfg_options, | 351 | cfg_options.clone(), |
341 | env, | 352 | env, |
342 | extern_source, | 353 | extern_source, |
343 | proc_macro, | 354 | proc_macro, |
@@ -368,6 +379,10 @@ impl ProjectWorkspace { | |||
368 | 379 | ||
369 | let mut pkg_to_lib_crate = FxHashMap::default(); | 380 | let mut pkg_to_lib_crate = FxHashMap::default(); |
370 | let mut pkg_crates = FxHashMap::default(); | 381 | let mut pkg_crates = FxHashMap::default(); |
382 | |||
383 | // Add test cfg for non-sysroot crates | ||
384 | cfg_options.insert_atom("test".into()); | ||
385 | |||
371 | // Next, create crates for each package, target pair | 386 | // Next, create crates for each package, target pair |
372 | for pkg in cargo.packages() { | 387 | for pkg in cargo.packages() { |
373 | let mut lib_tgt = None; | 388 | let mut lib_tgt = None; |
@@ -376,7 +391,7 @@ impl ProjectWorkspace { | |||
376 | if let Some(file_id) = load(root) { | 391 | if let Some(file_id) = load(root) { |
377 | let edition = cargo[pkg].edition; | 392 | let edition = cargo[pkg].edition; |
378 | let cfg_options = { | 393 | let cfg_options = { |
379 | let mut opts = default_cfg_options.clone(); | 394 | let mut opts = cfg_options.clone(); |
380 | for feature in cargo[pkg].features.iter() { | 395 | for feature in cargo[pkg].features.iter() { |
381 | opts.insert_key_value("feature".into(), feature.into()); | 396 | opts.insert_key_value("feature".into(), feature.into()); |
382 | } | 397 | } |
@@ -533,7 +548,7 @@ impl ProjectWorkspace { | |||
533 | } | 548 | } |
534 | } | 549 | } |
535 | 550 | ||
536 | pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | 551 | fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { |
537 | let mut cfg_options = CfgOptions::default(); | 552 | let mut cfg_options = CfgOptions::default(); |
538 | 553 | ||
539 | // Some nightly-only cfgs, which are required for stdlib | 554 | // Some nightly-only cfgs, which are required for stdlib |
@@ -551,7 +566,7 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | |||
551 | let mut cmd = Command::new(ra_toolchain::rustc()); | 566 | let mut cmd = Command::new(ra_toolchain::rustc()); |
552 | cmd.args(&["--print", "cfg", "-O"]); | 567 | cmd.args(&["--print", "cfg", "-O"]); |
553 | if let Some(target) = target { | 568 | if let Some(target) = target { |
554 | cmd.args(&["--target", target.as_str()]); | 569 | cmd.args(&["--target", target]); |
555 | } | 570 | } |
556 | let output = output(cmd)?; | 571 | let output = output(cmd)?; |
557 | Ok(String::from_utf8(output.stdout)?) | 572 | Ok(String::from_utf8(output.stdout)?) |
@@ -573,6 +588,8 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | |||
573 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | 588 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), |
574 | } | 589 | } |
575 | 590 | ||
591 | cfg_options.insert_atom("debug_assertions".into()); | ||
592 | |||
576 | cfg_options | 593 | cfg_options |
577 | } | 594 | } |
578 | 595 | ||
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 1876afe95..9d02aeef3 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -75,7 +75,7 @@ impl<N> AstChildren<N> { | |||
75 | impl<N: AstNode> Iterator for AstChildren<N> { | 75 | impl<N: AstNode> Iterator for AstChildren<N> { |
76 | type Item = N; | 76 | type Item = N; |
77 | fn next(&mut self) -> Option<N> { | 77 | fn next(&mut self) -> Option<N> { |
78 | self.inner.by_ref().find_map(N::cast) | 78 | self.inner.find_map(N::cast) |
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
@@ -285,6 +285,8 @@ where | |||
285 | let pred = predicates.next().unwrap(); | 285 | let pred = predicates.next().unwrap(); |
286 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | 286 | let mut bounds = pred.type_bound_list().unwrap().bounds(); |
287 | 287 | ||
288 | assert!(pred.for_token().is_none()); | ||
289 | assert!(pred.type_param_list().is_none()); | ||
288 | assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); | 290 | assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); |
289 | assert_bound("Clone", bounds.next()); | 291 | assert_bound("Clone", bounds.next()); |
290 | assert_bound("Copy", bounds.next()); | 292 | assert_bound("Copy", bounds.next()); |
@@ -322,6 +324,8 @@ where | |||
322 | let pred = predicates.next().unwrap(); | 324 | let pred = predicates.next().unwrap(); |
323 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | 325 | let mut bounds = pred.type_bound_list().unwrap().bounds(); |
324 | 326 | ||
325 | assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string()); | 327 | assert!(pred.for_token().is_some()); |
328 | assert_eq!("<'a>", pred.type_param_list().unwrap().syntax().text().to_string()); | ||
329 | assert_eq!("F", pred.type_ref().unwrap().syntax().text().to_string()); | ||
326 | assert_bound("Fn(&'a str)", bounds.next()); | 330 | assert_bound("Fn(&'a str)", bounds.next()); |
327 | } | 331 | } |
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 29eb3fcb9..2ef173a03 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -579,12 +579,17 @@ pub trait AstNodeEdit: AstNode + Clone + Sized { | |||
579 | rewriter.rewrite_ast(self) | 579 | rewriter.rewrite_ast(self) |
580 | } | 580 | } |
581 | #[must_use] | 581 | #[must_use] |
582 | fn indent(&self, indent: IndentLevel) -> Self { | 582 | fn indent(&self, level: IndentLevel) -> Self { |
583 | Self::cast(indent.increase_indent(self.syntax().clone())).unwrap() | 583 | Self::cast(level.increase_indent(self.syntax().clone())).unwrap() |
584 | } | 584 | } |
585 | #[must_use] | 585 | #[must_use] |
586 | fn dedent(&self, indent: IndentLevel) -> Self { | 586 | fn dedent(&self, level: IndentLevel) -> Self { |
587 | Self::cast(indent.decrease_indent(self.syntax().clone())).unwrap() | 587 | Self::cast(level.decrease_indent(self.syntax().clone())).unwrap() |
588 | } | ||
589 | #[must_use] | ||
590 | fn reset_indent(&self) -> Self { | ||
591 | let level = IndentLevel::from_node(self.syntax()); | ||
592 | self.dedent(level) | ||
588 | } | 593 | } |
589 | } | 594 | } |
590 | 595 | ||
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index cb430ca01..58141da11 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -2052,6 +2052,8 @@ pub struct WherePred { | |||
2052 | } | 2052 | } |
2053 | impl ast::TypeBoundsOwner for WherePred {} | 2053 | impl ast::TypeBoundsOwner for WherePred {} |
2054 | impl WherePred { | 2054 | impl WherePred { |
2055 | pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } | ||
2056 | pub fn type_param_list(&self) -> Option<TypeParamList> { support::child(&self.syntax) } | ||
2055 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | 2057 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { |
2056 | support::token(&self.syntax, T![lifetime]) | 2058 | support::token(&self.syntax, T![lifetime]) |
2057 | } | 2059 | } |
@@ -4849,687 +4851,687 @@ impl AstNode for FieldDefList { | |||
4849 | } | 4851 | } |
4850 | } | 4852 | } |
4851 | impl std::fmt::Display for NominalDef { | 4853 | impl std::fmt::Display for NominalDef { |
4852 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4854 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4853 | std::fmt::Display::fmt(self.syntax(), f) | 4855 | std::fmt::Display::fmt(self.syntax(), f) |
4854 | } | 4856 | } |
4855 | } | 4857 | } |
4856 | impl std::fmt::Display for GenericParam { | 4858 | impl std::fmt::Display for GenericParam { |
4857 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4859 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4858 | std::fmt::Display::fmt(self.syntax(), f) | 4860 | std::fmt::Display::fmt(self.syntax(), f) |
4859 | } | 4861 | } |
4860 | } | 4862 | } |
4861 | impl std::fmt::Display for GenericArg { | 4863 | impl std::fmt::Display for GenericArg { |
4862 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4864 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4863 | std::fmt::Display::fmt(self.syntax(), f) | 4865 | std::fmt::Display::fmt(self.syntax(), f) |
4864 | } | 4866 | } |
4865 | } | 4867 | } |
4866 | impl std::fmt::Display for TypeRef { | 4868 | impl std::fmt::Display for TypeRef { |
4867 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4869 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4868 | std::fmt::Display::fmt(self.syntax(), f) | 4870 | std::fmt::Display::fmt(self.syntax(), f) |
4869 | } | 4871 | } |
4870 | } | 4872 | } |
4871 | impl std::fmt::Display for ModuleItem { | 4873 | impl std::fmt::Display for ModuleItem { |
4872 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4874 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4873 | std::fmt::Display::fmt(self.syntax(), f) | 4875 | std::fmt::Display::fmt(self.syntax(), f) |
4874 | } | 4876 | } |
4875 | } | 4877 | } |
4876 | impl std::fmt::Display for AssocItem { | 4878 | impl std::fmt::Display for AssocItem { |
4877 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4879 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4878 | std::fmt::Display::fmt(self.syntax(), f) | 4880 | std::fmt::Display::fmt(self.syntax(), f) |
4879 | } | 4881 | } |
4880 | } | 4882 | } |
4881 | impl std::fmt::Display for ExternItem { | 4883 | impl std::fmt::Display for ExternItem { |
4882 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4884 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4883 | std::fmt::Display::fmt(self.syntax(), f) | 4885 | std::fmt::Display::fmt(self.syntax(), f) |
4884 | } | 4886 | } |
4885 | } | 4887 | } |
4886 | impl std::fmt::Display for Expr { | 4888 | impl std::fmt::Display for Expr { |
4887 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4889 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4888 | std::fmt::Display::fmt(self.syntax(), f) | 4890 | std::fmt::Display::fmt(self.syntax(), f) |
4889 | } | 4891 | } |
4890 | } | 4892 | } |
4891 | impl std::fmt::Display for Pat { | 4893 | impl std::fmt::Display for Pat { |
4892 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4894 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4893 | std::fmt::Display::fmt(self.syntax(), f) | 4895 | std::fmt::Display::fmt(self.syntax(), f) |
4894 | } | 4896 | } |
4895 | } | 4897 | } |
4896 | impl std::fmt::Display for RecordInnerPat { | 4898 | impl std::fmt::Display for RecordInnerPat { |
4897 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4899 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4898 | std::fmt::Display::fmt(self.syntax(), f) | 4900 | std::fmt::Display::fmt(self.syntax(), f) |
4899 | } | 4901 | } |
4900 | } | 4902 | } |
4901 | impl std::fmt::Display for AttrInput { | 4903 | impl std::fmt::Display for AttrInput { |
4902 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4904 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4903 | std::fmt::Display::fmt(self.syntax(), f) | 4905 | std::fmt::Display::fmt(self.syntax(), f) |
4904 | } | 4906 | } |
4905 | } | 4907 | } |
4906 | impl std::fmt::Display for Stmt { | 4908 | impl std::fmt::Display for Stmt { |
4907 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4909 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4908 | std::fmt::Display::fmt(self.syntax(), f) | 4910 | std::fmt::Display::fmt(self.syntax(), f) |
4909 | } | 4911 | } |
4910 | } | 4912 | } |
4911 | impl std::fmt::Display for FieldDefList { | 4913 | impl std::fmt::Display for FieldDefList { |
4912 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4914 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4913 | std::fmt::Display::fmt(self.syntax(), f) | 4915 | std::fmt::Display::fmt(self.syntax(), f) |
4914 | } | 4916 | } |
4915 | } | 4917 | } |
4916 | impl std::fmt::Display for SourceFile { | 4918 | impl std::fmt::Display for SourceFile { |
4917 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4919 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4918 | std::fmt::Display::fmt(self.syntax(), f) | 4920 | std::fmt::Display::fmt(self.syntax(), f) |
4919 | } | 4921 | } |
4920 | } | 4922 | } |
4921 | impl std::fmt::Display for FnDef { | 4923 | impl std::fmt::Display for FnDef { |
4922 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4924 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4923 | std::fmt::Display::fmt(self.syntax(), f) | 4925 | std::fmt::Display::fmt(self.syntax(), f) |
4924 | } | 4926 | } |
4925 | } | 4927 | } |
4926 | impl std::fmt::Display for RetType { | 4928 | impl std::fmt::Display for RetType { |
4927 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4929 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4928 | std::fmt::Display::fmt(self.syntax(), f) | 4930 | std::fmt::Display::fmt(self.syntax(), f) |
4929 | } | 4931 | } |
4930 | } | 4932 | } |
4931 | impl std::fmt::Display for StructDef { | 4933 | impl std::fmt::Display for StructDef { |
4932 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4934 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4933 | std::fmt::Display::fmt(self.syntax(), f) | 4935 | std::fmt::Display::fmt(self.syntax(), f) |
4934 | } | 4936 | } |
4935 | } | 4937 | } |
4936 | impl std::fmt::Display for UnionDef { | 4938 | impl std::fmt::Display for UnionDef { |
4937 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4939 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4938 | std::fmt::Display::fmt(self.syntax(), f) | 4940 | std::fmt::Display::fmt(self.syntax(), f) |
4939 | } | 4941 | } |
4940 | } | 4942 | } |
4941 | impl std::fmt::Display for RecordFieldDefList { | 4943 | impl std::fmt::Display for RecordFieldDefList { |
4942 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4944 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4943 | std::fmt::Display::fmt(self.syntax(), f) | 4945 | std::fmt::Display::fmt(self.syntax(), f) |
4944 | } | 4946 | } |
4945 | } | 4947 | } |
4946 | impl std::fmt::Display for RecordFieldDef { | 4948 | impl std::fmt::Display for RecordFieldDef { |
4947 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4949 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4948 | std::fmt::Display::fmt(self.syntax(), f) | 4950 | std::fmt::Display::fmt(self.syntax(), f) |
4949 | } | 4951 | } |
4950 | } | 4952 | } |
4951 | impl std::fmt::Display for TupleFieldDefList { | 4953 | impl std::fmt::Display for TupleFieldDefList { |
4952 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4954 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4953 | std::fmt::Display::fmt(self.syntax(), f) | 4955 | std::fmt::Display::fmt(self.syntax(), f) |
4954 | } | 4956 | } |
4955 | } | 4957 | } |
4956 | impl std::fmt::Display for TupleFieldDef { | 4958 | impl std::fmt::Display for TupleFieldDef { |
4957 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4959 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4958 | std::fmt::Display::fmt(self.syntax(), f) | 4960 | std::fmt::Display::fmt(self.syntax(), f) |
4959 | } | 4961 | } |
4960 | } | 4962 | } |
4961 | impl std::fmt::Display for EnumDef { | 4963 | impl std::fmt::Display for EnumDef { |
4962 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4964 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4963 | std::fmt::Display::fmt(self.syntax(), f) | 4965 | std::fmt::Display::fmt(self.syntax(), f) |
4964 | } | 4966 | } |
4965 | } | 4967 | } |
4966 | impl std::fmt::Display for EnumVariantList { | 4968 | impl std::fmt::Display for EnumVariantList { |
4967 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4969 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4968 | std::fmt::Display::fmt(self.syntax(), f) | 4970 | std::fmt::Display::fmt(self.syntax(), f) |
4969 | } | 4971 | } |
4970 | } | 4972 | } |
4971 | impl std::fmt::Display for EnumVariant { | 4973 | impl std::fmt::Display for EnumVariant { |
4972 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4974 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4973 | std::fmt::Display::fmt(self.syntax(), f) | 4975 | std::fmt::Display::fmt(self.syntax(), f) |
4974 | } | 4976 | } |
4975 | } | 4977 | } |
4976 | impl std::fmt::Display for TraitDef { | 4978 | impl std::fmt::Display for TraitDef { |
4977 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4979 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4978 | std::fmt::Display::fmt(self.syntax(), f) | 4980 | std::fmt::Display::fmt(self.syntax(), f) |
4979 | } | 4981 | } |
4980 | } | 4982 | } |
4981 | impl std::fmt::Display for Module { | 4983 | impl std::fmt::Display for Module { |
4982 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4984 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4983 | std::fmt::Display::fmt(self.syntax(), f) | 4985 | std::fmt::Display::fmt(self.syntax(), f) |
4984 | } | 4986 | } |
4985 | } | 4987 | } |
4986 | impl std::fmt::Display for ItemList { | 4988 | impl std::fmt::Display for ItemList { |
4987 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4989 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4988 | std::fmt::Display::fmt(self.syntax(), f) | 4990 | std::fmt::Display::fmt(self.syntax(), f) |
4989 | } | 4991 | } |
4990 | } | 4992 | } |
4991 | impl std::fmt::Display for ConstDef { | 4993 | impl std::fmt::Display for ConstDef { |
4992 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4994 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4993 | std::fmt::Display::fmt(self.syntax(), f) | 4995 | std::fmt::Display::fmt(self.syntax(), f) |
4994 | } | 4996 | } |
4995 | } | 4997 | } |
4996 | impl std::fmt::Display for StaticDef { | 4998 | impl std::fmt::Display for StaticDef { |
4997 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 4999 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
4998 | std::fmt::Display::fmt(self.syntax(), f) | 5000 | std::fmt::Display::fmt(self.syntax(), f) |
4999 | } | 5001 | } |
5000 | } | 5002 | } |
5001 | impl std::fmt::Display for TypeAliasDef { | 5003 | impl std::fmt::Display for TypeAliasDef { |
5002 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5004 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5003 | std::fmt::Display::fmt(self.syntax(), f) | 5005 | std::fmt::Display::fmt(self.syntax(), f) |
5004 | } | 5006 | } |
5005 | } | 5007 | } |
5006 | impl std::fmt::Display for ImplDef { | 5008 | impl std::fmt::Display for ImplDef { |
5007 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5009 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5008 | std::fmt::Display::fmt(self.syntax(), f) | 5010 | std::fmt::Display::fmt(self.syntax(), f) |
5009 | } | 5011 | } |
5010 | } | 5012 | } |
5011 | impl std::fmt::Display for ParenType { | 5013 | impl std::fmt::Display for ParenType { |
5012 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5014 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5013 | std::fmt::Display::fmt(self.syntax(), f) | 5015 | std::fmt::Display::fmt(self.syntax(), f) |
5014 | } | 5016 | } |
5015 | } | 5017 | } |
5016 | impl std::fmt::Display for TupleType { | 5018 | impl std::fmt::Display for TupleType { |
5017 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5019 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5018 | std::fmt::Display::fmt(self.syntax(), f) | 5020 | std::fmt::Display::fmt(self.syntax(), f) |
5019 | } | 5021 | } |
5020 | } | 5022 | } |
5021 | impl std::fmt::Display for NeverType { | 5023 | impl std::fmt::Display for NeverType { |
5022 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5024 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5023 | std::fmt::Display::fmt(self.syntax(), f) | 5025 | std::fmt::Display::fmt(self.syntax(), f) |
5024 | } | 5026 | } |
5025 | } | 5027 | } |
5026 | impl std::fmt::Display for PathType { | 5028 | impl std::fmt::Display for PathType { |
5027 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5029 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5028 | std::fmt::Display::fmt(self.syntax(), f) | 5030 | std::fmt::Display::fmt(self.syntax(), f) |
5029 | } | 5031 | } |
5030 | } | 5032 | } |
5031 | impl std::fmt::Display for PointerType { | 5033 | impl std::fmt::Display for PointerType { |
5032 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5034 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5033 | std::fmt::Display::fmt(self.syntax(), f) | 5035 | std::fmt::Display::fmt(self.syntax(), f) |
5034 | } | 5036 | } |
5035 | } | 5037 | } |
5036 | impl std::fmt::Display for ArrayType { | 5038 | impl std::fmt::Display for ArrayType { |
5037 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5039 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5038 | std::fmt::Display::fmt(self.syntax(), f) | 5040 | std::fmt::Display::fmt(self.syntax(), f) |
5039 | } | 5041 | } |
5040 | } | 5042 | } |
5041 | impl std::fmt::Display for SliceType { | 5043 | impl std::fmt::Display for SliceType { |
5042 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5044 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5043 | std::fmt::Display::fmt(self.syntax(), f) | 5045 | std::fmt::Display::fmt(self.syntax(), f) |
5044 | } | 5046 | } |
5045 | } | 5047 | } |
5046 | impl std::fmt::Display for ReferenceType { | 5048 | impl std::fmt::Display for ReferenceType { |
5047 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5049 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5048 | std::fmt::Display::fmt(self.syntax(), f) | 5050 | std::fmt::Display::fmt(self.syntax(), f) |
5049 | } | 5051 | } |
5050 | } | 5052 | } |
5051 | impl std::fmt::Display for PlaceholderType { | 5053 | impl std::fmt::Display for PlaceholderType { |
5052 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5054 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5053 | std::fmt::Display::fmt(self.syntax(), f) | 5055 | std::fmt::Display::fmt(self.syntax(), f) |
5054 | } | 5056 | } |
5055 | } | 5057 | } |
5056 | impl std::fmt::Display for FnPointerType { | 5058 | impl std::fmt::Display for FnPointerType { |
5057 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5059 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5058 | std::fmt::Display::fmt(self.syntax(), f) | 5060 | std::fmt::Display::fmt(self.syntax(), f) |
5059 | } | 5061 | } |
5060 | } | 5062 | } |
5061 | impl std::fmt::Display for ForType { | 5063 | impl std::fmt::Display for ForType { |
5062 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5064 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5063 | std::fmt::Display::fmt(self.syntax(), f) | 5065 | std::fmt::Display::fmt(self.syntax(), f) |
5064 | } | 5066 | } |
5065 | } | 5067 | } |
5066 | impl std::fmt::Display for ImplTraitType { | 5068 | impl std::fmt::Display for ImplTraitType { |
5067 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5069 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5068 | std::fmt::Display::fmt(self.syntax(), f) | 5070 | std::fmt::Display::fmt(self.syntax(), f) |
5069 | } | 5071 | } |
5070 | } | 5072 | } |
5071 | impl std::fmt::Display for DynTraitType { | 5073 | impl std::fmt::Display for DynTraitType { |
5072 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5074 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5073 | std::fmt::Display::fmt(self.syntax(), f) | 5075 | std::fmt::Display::fmt(self.syntax(), f) |
5074 | } | 5076 | } |
5075 | } | 5077 | } |
5076 | impl std::fmt::Display for TupleExpr { | 5078 | impl std::fmt::Display for TupleExpr { |
5077 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5079 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5078 | std::fmt::Display::fmt(self.syntax(), f) | 5080 | std::fmt::Display::fmt(self.syntax(), f) |
5079 | } | 5081 | } |
5080 | } | 5082 | } |
5081 | impl std::fmt::Display for ArrayExpr { | 5083 | impl std::fmt::Display for ArrayExpr { |
5082 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5084 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5083 | std::fmt::Display::fmt(self.syntax(), f) | 5085 | std::fmt::Display::fmt(self.syntax(), f) |
5084 | } | 5086 | } |
5085 | } | 5087 | } |
5086 | impl std::fmt::Display for ParenExpr { | 5088 | impl std::fmt::Display for ParenExpr { |
5087 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5089 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5088 | std::fmt::Display::fmt(self.syntax(), f) | 5090 | std::fmt::Display::fmt(self.syntax(), f) |
5089 | } | 5091 | } |
5090 | } | 5092 | } |
5091 | impl std::fmt::Display for PathExpr { | 5093 | impl std::fmt::Display for PathExpr { |
5092 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5094 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5093 | std::fmt::Display::fmt(self.syntax(), f) | 5095 | std::fmt::Display::fmt(self.syntax(), f) |
5094 | } | 5096 | } |
5095 | } | 5097 | } |
5096 | impl std::fmt::Display for LambdaExpr { | 5098 | impl std::fmt::Display for LambdaExpr { |
5097 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5099 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5098 | std::fmt::Display::fmt(self.syntax(), f) | 5100 | std::fmt::Display::fmt(self.syntax(), f) |
5099 | } | 5101 | } |
5100 | } | 5102 | } |
5101 | impl std::fmt::Display for IfExpr { | 5103 | impl std::fmt::Display for IfExpr { |
5102 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5104 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5103 | std::fmt::Display::fmt(self.syntax(), f) | 5105 | std::fmt::Display::fmt(self.syntax(), f) |
5104 | } | 5106 | } |
5105 | } | 5107 | } |
5106 | impl std::fmt::Display for LoopExpr { | 5108 | impl std::fmt::Display for LoopExpr { |
5107 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5109 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5108 | std::fmt::Display::fmt(self.syntax(), f) | 5110 | std::fmt::Display::fmt(self.syntax(), f) |
5109 | } | 5111 | } |
5110 | } | 5112 | } |
5111 | impl std::fmt::Display for EffectExpr { | 5113 | impl std::fmt::Display for EffectExpr { |
5112 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5114 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5113 | std::fmt::Display::fmt(self.syntax(), f) | 5115 | std::fmt::Display::fmt(self.syntax(), f) |
5114 | } | 5116 | } |
5115 | } | 5117 | } |
5116 | impl std::fmt::Display for ForExpr { | 5118 | impl std::fmt::Display for ForExpr { |
5117 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5119 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5118 | std::fmt::Display::fmt(self.syntax(), f) | 5120 | std::fmt::Display::fmt(self.syntax(), f) |
5119 | } | 5121 | } |
5120 | } | 5122 | } |
5121 | impl std::fmt::Display for WhileExpr { | 5123 | impl std::fmt::Display for WhileExpr { |
5122 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5124 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5123 | std::fmt::Display::fmt(self.syntax(), f) | 5125 | std::fmt::Display::fmt(self.syntax(), f) |
5124 | } | 5126 | } |
5125 | } | 5127 | } |
5126 | impl std::fmt::Display for ContinueExpr { | 5128 | impl std::fmt::Display for ContinueExpr { |
5127 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5129 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5128 | std::fmt::Display::fmt(self.syntax(), f) | 5130 | std::fmt::Display::fmt(self.syntax(), f) |
5129 | } | 5131 | } |
5130 | } | 5132 | } |
5131 | impl std::fmt::Display for BreakExpr { | 5133 | impl std::fmt::Display for BreakExpr { |
5132 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5134 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5133 | std::fmt::Display::fmt(self.syntax(), f) | 5135 | std::fmt::Display::fmt(self.syntax(), f) |
5134 | } | 5136 | } |
5135 | } | 5137 | } |
5136 | impl std::fmt::Display for Label { | 5138 | impl std::fmt::Display for Label { |
5137 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5139 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5138 | std::fmt::Display::fmt(self.syntax(), f) | 5140 | std::fmt::Display::fmt(self.syntax(), f) |
5139 | } | 5141 | } |
5140 | } | 5142 | } |
5141 | impl std::fmt::Display for BlockExpr { | 5143 | impl std::fmt::Display for BlockExpr { |
5142 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5144 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5143 | std::fmt::Display::fmt(self.syntax(), f) | 5145 | std::fmt::Display::fmt(self.syntax(), f) |
5144 | } | 5146 | } |
5145 | } | 5147 | } |
5146 | impl std::fmt::Display for ReturnExpr { | 5148 | impl std::fmt::Display for ReturnExpr { |
5147 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5149 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5148 | std::fmt::Display::fmt(self.syntax(), f) | 5150 | std::fmt::Display::fmt(self.syntax(), f) |
5149 | } | 5151 | } |
5150 | } | 5152 | } |
5151 | impl std::fmt::Display for CallExpr { | 5153 | impl std::fmt::Display for CallExpr { |
5152 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5154 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5153 | std::fmt::Display::fmt(self.syntax(), f) | 5155 | std::fmt::Display::fmt(self.syntax(), f) |
5154 | } | 5156 | } |
5155 | } | 5157 | } |
5156 | impl std::fmt::Display for MethodCallExpr { | 5158 | impl std::fmt::Display for MethodCallExpr { |
5157 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5159 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5158 | std::fmt::Display::fmt(self.syntax(), f) | 5160 | std::fmt::Display::fmt(self.syntax(), f) |
5159 | } | 5161 | } |
5160 | } | 5162 | } |
5161 | impl std::fmt::Display for IndexExpr { | 5163 | impl std::fmt::Display for IndexExpr { |
5162 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5164 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5163 | std::fmt::Display::fmt(self.syntax(), f) | 5165 | std::fmt::Display::fmt(self.syntax(), f) |
5164 | } | 5166 | } |
5165 | } | 5167 | } |
5166 | impl std::fmt::Display for FieldExpr { | 5168 | impl std::fmt::Display for FieldExpr { |
5167 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5169 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5168 | std::fmt::Display::fmt(self.syntax(), f) | 5170 | std::fmt::Display::fmt(self.syntax(), f) |
5169 | } | 5171 | } |
5170 | } | 5172 | } |
5171 | impl std::fmt::Display for AwaitExpr { | 5173 | impl std::fmt::Display for AwaitExpr { |
5172 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5174 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5173 | std::fmt::Display::fmt(self.syntax(), f) | 5175 | std::fmt::Display::fmt(self.syntax(), f) |
5174 | } | 5176 | } |
5175 | } | 5177 | } |
5176 | impl std::fmt::Display for TryExpr { | 5178 | impl std::fmt::Display for TryExpr { |
5177 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5179 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5178 | std::fmt::Display::fmt(self.syntax(), f) | 5180 | std::fmt::Display::fmt(self.syntax(), f) |
5179 | } | 5181 | } |
5180 | } | 5182 | } |
5181 | impl std::fmt::Display for CastExpr { | 5183 | impl std::fmt::Display for CastExpr { |
5182 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5184 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5183 | std::fmt::Display::fmt(self.syntax(), f) | 5185 | std::fmt::Display::fmt(self.syntax(), f) |
5184 | } | 5186 | } |
5185 | } | 5187 | } |
5186 | impl std::fmt::Display for RefExpr { | 5188 | impl std::fmt::Display for RefExpr { |
5187 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5189 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5188 | std::fmt::Display::fmt(self.syntax(), f) | 5190 | std::fmt::Display::fmt(self.syntax(), f) |
5189 | } | 5191 | } |
5190 | } | 5192 | } |
5191 | impl std::fmt::Display for PrefixExpr { | 5193 | impl std::fmt::Display for PrefixExpr { |
5192 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5194 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5193 | std::fmt::Display::fmt(self.syntax(), f) | 5195 | std::fmt::Display::fmt(self.syntax(), f) |
5194 | } | 5196 | } |
5195 | } | 5197 | } |
5196 | impl std::fmt::Display for BoxExpr { | 5198 | impl std::fmt::Display for BoxExpr { |
5197 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5199 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5198 | std::fmt::Display::fmt(self.syntax(), f) | 5200 | std::fmt::Display::fmt(self.syntax(), f) |
5199 | } | 5201 | } |
5200 | } | 5202 | } |
5201 | impl std::fmt::Display for RangeExpr { | 5203 | impl std::fmt::Display for RangeExpr { |
5202 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5204 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5203 | std::fmt::Display::fmt(self.syntax(), f) | 5205 | std::fmt::Display::fmt(self.syntax(), f) |
5204 | } | 5206 | } |
5205 | } | 5207 | } |
5206 | impl std::fmt::Display for BinExpr { | 5208 | impl std::fmt::Display for BinExpr { |
5207 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5209 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5208 | std::fmt::Display::fmt(self.syntax(), f) | 5210 | std::fmt::Display::fmt(self.syntax(), f) |
5209 | } | 5211 | } |
5210 | } | 5212 | } |
5211 | impl std::fmt::Display for Literal { | 5213 | impl std::fmt::Display for Literal { |
5212 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5214 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5213 | std::fmt::Display::fmt(self.syntax(), f) | 5215 | std::fmt::Display::fmt(self.syntax(), f) |
5214 | } | 5216 | } |
5215 | } | 5217 | } |
5216 | impl std::fmt::Display for MatchExpr { | 5218 | impl std::fmt::Display for MatchExpr { |
5217 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5219 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5218 | std::fmt::Display::fmt(self.syntax(), f) | 5220 | std::fmt::Display::fmt(self.syntax(), f) |
5219 | } | 5221 | } |
5220 | } | 5222 | } |
5221 | impl std::fmt::Display for MatchArmList { | 5223 | impl std::fmt::Display for MatchArmList { |
5222 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5224 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5223 | std::fmt::Display::fmt(self.syntax(), f) | 5225 | std::fmt::Display::fmt(self.syntax(), f) |
5224 | } | 5226 | } |
5225 | } | 5227 | } |
5226 | impl std::fmt::Display for MatchArm { | 5228 | impl std::fmt::Display for MatchArm { |
5227 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5229 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5228 | std::fmt::Display::fmt(self.syntax(), f) | 5230 | std::fmt::Display::fmt(self.syntax(), f) |
5229 | } | 5231 | } |
5230 | } | 5232 | } |
5231 | impl std::fmt::Display for MatchGuard { | 5233 | impl std::fmt::Display for MatchGuard { |
5232 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5234 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5233 | std::fmt::Display::fmt(self.syntax(), f) | 5235 | std::fmt::Display::fmt(self.syntax(), f) |
5234 | } | 5236 | } |
5235 | } | 5237 | } |
5236 | impl std::fmt::Display for RecordLit { | 5238 | impl std::fmt::Display for RecordLit { |
5237 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5239 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5238 | std::fmt::Display::fmt(self.syntax(), f) | 5240 | std::fmt::Display::fmt(self.syntax(), f) |
5239 | } | 5241 | } |
5240 | } | 5242 | } |
5241 | impl std::fmt::Display for RecordFieldList { | 5243 | impl std::fmt::Display for RecordFieldList { |
5242 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5244 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5243 | std::fmt::Display::fmt(self.syntax(), f) | 5245 | std::fmt::Display::fmt(self.syntax(), f) |
5244 | } | 5246 | } |
5245 | } | 5247 | } |
5246 | impl std::fmt::Display for RecordField { | 5248 | impl std::fmt::Display for RecordField { |
5247 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5249 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5248 | std::fmt::Display::fmt(self.syntax(), f) | 5250 | std::fmt::Display::fmt(self.syntax(), f) |
5249 | } | 5251 | } |
5250 | } | 5252 | } |
5251 | impl std::fmt::Display for OrPat { | 5253 | impl std::fmt::Display for OrPat { |
5252 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5254 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5253 | std::fmt::Display::fmt(self.syntax(), f) | 5255 | std::fmt::Display::fmt(self.syntax(), f) |
5254 | } | 5256 | } |
5255 | } | 5257 | } |
5256 | impl std::fmt::Display for ParenPat { | 5258 | impl std::fmt::Display for ParenPat { |
5257 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5259 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5258 | std::fmt::Display::fmt(self.syntax(), f) | 5260 | std::fmt::Display::fmt(self.syntax(), f) |
5259 | } | 5261 | } |
5260 | } | 5262 | } |
5261 | impl std::fmt::Display for RefPat { | 5263 | impl std::fmt::Display for RefPat { |
5262 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5264 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5263 | std::fmt::Display::fmt(self.syntax(), f) | 5265 | std::fmt::Display::fmt(self.syntax(), f) |
5264 | } | 5266 | } |
5265 | } | 5267 | } |
5266 | impl std::fmt::Display for BoxPat { | 5268 | impl std::fmt::Display for BoxPat { |
5267 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5269 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5268 | std::fmt::Display::fmt(self.syntax(), f) | 5270 | std::fmt::Display::fmt(self.syntax(), f) |
5269 | } | 5271 | } |
5270 | } | 5272 | } |
5271 | impl std::fmt::Display for BindPat { | 5273 | impl std::fmt::Display for BindPat { |
5272 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5274 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5273 | std::fmt::Display::fmt(self.syntax(), f) | 5275 | std::fmt::Display::fmt(self.syntax(), f) |
5274 | } | 5276 | } |
5275 | } | 5277 | } |
5276 | impl std::fmt::Display for PlaceholderPat { | 5278 | impl std::fmt::Display for PlaceholderPat { |
5277 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5279 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5278 | std::fmt::Display::fmt(self.syntax(), f) | 5280 | std::fmt::Display::fmt(self.syntax(), f) |
5279 | } | 5281 | } |
5280 | } | 5282 | } |
5281 | impl std::fmt::Display for DotDotPat { | 5283 | impl std::fmt::Display for DotDotPat { |
5282 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5284 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5283 | std::fmt::Display::fmt(self.syntax(), f) | 5285 | std::fmt::Display::fmt(self.syntax(), f) |
5284 | } | 5286 | } |
5285 | } | 5287 | } |
5286 | impl std::fmt::Display for PathPat { | 5288 | impl std::fmt::Display for PathPat { |
5287 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5289 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5288 | std::fmt::Display::fmt(self.syntax(), f) | 5290 | std::fmt::Display::fmt(self.syntax(), f) |
5289 | } | 5291 | } |
5290 | } | 5292 | } |
5291 | impl std::fmt::Display for SlicePat { | 5293 | impl std::fmt::Display for SlicePat { |
5292 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5294 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5293 | std::fmt::Display::fmt(self.syntax(), f) | 5295 | std::fmt::Display::fmt(self.syntax(), f) |
5294 | } | 5296 | } |
5295 | } | 5297 | } |
5296 | impl std::fmt::Display for RangePat { | 5298 | impl std::fmt::Display for RangePat { |
5297 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5299 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5298 | std::fmt::Display::fmt(self.syntax(), f) | 5300 | std::fmt::Display::fmt(self.syntax(), f) |
5299 | } | 5301 | } |
5300 | } | 5302 | } |
5301 | impl std::fmt::Display for LiteralPat { | 5303 | impl std::fmt::Display for LiteralPat { |
5302 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5304 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5303 | std::fmt::Display::fmt(self.syntax(), f) | 5305 | std::fmt::Display::fmt(self.syntax(), f) |
5304 | } | 5306 | } |
5305 | } | 5307 | } |
5306 | impl std::fmt::Display for MacroPat { | 5308 | impl std::fmt::Display for MacroPat { |
5307 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5309 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5308 | std::fmt::Display::fmt(self.syntax(), f) | 5310 | std::fmt::Display::fmt(self.syntax(), f) |
5309 | } | 5311 | } |
5310 | } | 5312 | } |
5311 | impl std::fmt::Display for RecordPat { | 5313 | impl std::fmt::Display for RecordPat { |
5312 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5314 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5313 | std::fmt::Display::fmt(self.syntax(), f) | 5315 | std::fmt::Display::fmt(self.syntax(), f) |
5314 | } | 5316 | } |
5315 | } | 5317 | } |
5316 | impl std::fmt::Display for RecordFieldPatList { | 5318 | impl std::fmt::Display for RecordFieldPatList { |
5317 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5319 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5318 | std::fmt::Display::fmt(self.syntax(), f) | 5320 | std::fmt::Display::fmt(self.syntax(), f) |
5319 | } | 5321 | } |
5320 | } | 5322 | } |
5321 | impl std::fmt::Display for RecordFieldPat { | 5323 | impl std::fmt::Display for RecordFieldPat { |
5322 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5324 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5323 | std::fmt::Display::fmt(self.syntax(), f) | 5325 | std::fmt::Display::fmt(self.syntax(), f) |
5324 | } | 5326 | } |
5325 | } | 5327 | } |
5326 | impl std::fmt::Display for TupleStructPat { | 5328 | impl std::fmt::Display for TupleStructPat { |
5327 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5329 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5328 | std::fmt::Display::fmt(self.syntax(), f) | 5330 | std::fmt::Display::fmt(self.syntax(), f) |
5329 | } | 5331 | } |
5330 | } | 5332 | } |
5331 | impl std::fmt::Display for TuplePat { | 5333 | impl std::fmt::Display for TuplePat { |
5332 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5334 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5333 | std::fmt::Display::fmt(self.syntax(), f) | 5335 | std::fmt::Display::fmt(self.syntax(), f) |
5334 | } | 5336 | } |
5335 | } | 5337 | } |
5336 | impl std::fmt::Display for Visibility { | 5338 | impl std::fmt::Display for Visibility { |
5337 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5339 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5338 | std::fmt::Display::fmt(self.syntax(), f) | 5340 | std::fmt::Display::fmt(self.syntax(), f) |
5339 | } | 5341 | } |
5340 | } | 5342 | } |
5341 | impl std::fmt::Display for Name { | 5343 | impl std::fmt::Display for Name { |
5342 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5344 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5343 | std::fmt::Display::fmt(self.syntax(), f) | 5345 | std::fmt::Display::fmt(self.syntax(), f) |
5344 | } | 5346 | } |
5345 | } | 5347 | } |
5346 | impl std::fmt::Display for NameRef { | 5348 | impl std::fmt::Display for NameRef { |
5347 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5349 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5348 | std::fmt::Display::fmt(self.syntax(), f) | 5350 | std::fmt::Display::fmt(self.syntax(), f) |
5349 | } | 5351 | } |
5350 | } | 5352 | } |
5351 | impl std::fmt::Display for MacroCall { | 5353 | impl std::fmt::Display for MacroCall { |
5352 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5354 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5353 | std::fmt::Display::fmt(self.syntax(), f) | 5355 | std::fmt::Display::fmt(self.syntax(), f) |
5354 | } | 5356 | } |
5355 | } | 5357 | } |
5356 | impl std::fmt::Display for Attr { | 5358 | impl std::fmt::Display for Attr { |
5357 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5359 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5358 | std::fmt::Display::fmt(self.syntax(), f) | 5360 | std::fmt::Display::fmt(self.syntax(), f) |
5359 | } | 5361 | } |
5360 | } | 5362 | } |
5361 | impl std::fmt::Display for TokenTree { | 5363 | impl std::fmt::Display for TokenTree { |
5362 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5364 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5363 | std::fmt::Display::fmt(self.syntax(), f) | 5365 | std::fmt::Display::fmt(self.syntax(), f) |
5364 | } | 5366 | } |
5365 | } | 5367 | } |
5366 | impl std::fmt::Display for TypeParamList { | 5368 | impl std::fmt::Display for TypeParamList { |
5367 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5369 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5368 | std::fmt::Display::fmt(self.syntax(), f) | 5370 | std::fmt::Display::fmt(self.syntax(), f) |
5369 | } | 5371 | } |
5370 | } | 5372 | } |
5371 | impl std::fmt::Display for TypeParam { | 5373 | impl std::fmt::Display for TypeParam { |
5372 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5374 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5373 | std::fmt::Display::fmt(self.syntax(), f) | 5375 | std::fmt::Display::fmt(self.syntax(), f) |
5374 | } | 5376 | } |
5375 | } | 5377 | } |
5376 | impl std::fmt::Display for ConstParam { | 5378 | impl std::fmt::Display for ConstParam { |
5377 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5379 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5378 | std::fmt::Display::fmt(self.syntax(), f) | 5380 | std::fmt::Display::fmt(self.syntax(), f) |
5379 | } | 5381 | } |
5380 | } | 5382 | } |
5381 | impl std::fmt::Display for LifetimeParam { | 5383 | impl std::fmt::Display for LifetimeParam { |
5382 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5384 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5383 | std::fmt::Display::fmt(self.syntax(), f) | 5385 | std::fmt::Display::fmt(self.syntax(), f) |
5384 | } | 5386 | } |
5385 | } | 5387 | } |
5386 | impl std::fmt::Display for TypeBound { | 5388 | impl std::fmt::Display for TypeBound { |
5387 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5389 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5388 | std::fmt::Display::fmt(self.syntax(), f) | 5390 | std::fmt::Display::fmt(self.syntax(), f) |
5389 | } | 5391 | } |
5390 | } | 5392 | } |
5391 | impl std::fmt::Display for TypeBoundList { | 5393 | impl std::fmt::Display for TypeBoundList { |
5392 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5394 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5393 | std::fmt::Display::fmt(self.syntax(), f) | 5395 | std::fmt::Display::fmt(self.syntax(), f) |
5394 | } | 5396 | } |
5395 | } | 5397 | } |
5396 | impl std::fmt::Display for WherePred { | 5398 | impl std::fmt::Display for WherePred { |
5397 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5399 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5398 | std::fmt::Display::fmt(self.syntax(), f) | 5400 | std::fmt::Display::fmt(self.syntax(), f) |
5399 | } | 5401 | } |
5400 | } | 5402 | } |
5401 | impl std::fmt::Display for WhereClause { | 5403 | impl std::fmt::Display for WhereClause { |
5402 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5404 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5403 | std::fmt::Display::fmt(self.syntax(), f) | 5405 | std::fmt::Display::fmt(self.syntax(), f) |
5404 | } | 5406 | } |
5405 | } | 5407 | } |
5406 | impl std::fmt::Display for Abi { | 5408 | impl std::fmt::Display for Abi { |
5407 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5409 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5408 | std::fmt::Display::fmt(self.syntax(), f) | 5410 | std::fmt::Display::fmt(self.syntax(), f) |
5409 | } | 5411 | } |
5410 | } | 5412 | } |
5411 | impl std::fmt::Display for ExprStmt { | 5413 | impl std::fmt::Display for ExprStmt { |
5412 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5414 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5413 | std::fmt::Display::fmt(self.syntax(), f) | 5415 | std::fmt::Display::fmt(self.syntax(), f) |
5414 | } | 5416 | } |
5415 | } | 5417 | } |
5416 | impl std::fmt::Display for LetStmt { | 5418 | impl std::fmt::Display for LetStmt { |
5417 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5419 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5418 | std::fmt::Display::fmt(self.syntax(), f) | 5420 | std::fmt::Display::fmt(self.syntax(), f) |
5419 | } | 5421 | } |
5420 | } | 5422 | } |
5421 | impl std::fmt::Display for Condition { | 5423 | impl std::fmt::Display for Condition { |
5422 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5424 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5423 | std::fmt::Display::fmt(self.syntax(), f) | 5425 | std::fmt::Display::fmt(self.syntax(), f) |
5424 | } | 5426 | } |
5425 | } | 5427 | } |
5426 | impl std::fmt::Display for ParamList { | 5428 | impl std::fmt::Display for ParamList { |
5427 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5429 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5428 | std::fmt::Display::fmt(self.syntax(), f) | 5430 | std::fmt::Display::fmt(self.syntax(), f) |
5429 | } | 5431 | } |
5430 | } | 5432 | } |
5431 | impl std::fmt::Display for SelfParam { | 5433 | impl std::fmt::Display for SelfParam { |
5432 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5434 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5433 | std::fmt::Display::fmt(self.syntax(), f) | 5435 | std::fmt::Display::fmt(self.syntax(), f) |
5434 | } | 5436 | } |
5435 | } | 5437 | } |
5436 | impl std::fmt::Display for Param { | 5438 | impl std::fmt::Display for Param { |
5437 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5439 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5438 | std::fmt::Display::fmt(self.syntax(), f) | 5440 | std::fmt::Display::fmt(self.syntax(), f) |
5439 | } | 5441 | } |
5440 | } | 5442 | } |
5441 | impl std::fmt::Display for UseItem { | 5443 | impl std::fmt::Display for UseItem { |
5442 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5444 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5443 | std::fmt::Display::fmt(self.syntax(), f) | 5445 | std::fmt::Display::fmt(self.syntax(), f) |
5444 | } | 5446 | } |
5445 | } | 5447 | } |
5446 | impl std::fmt::Display for UseTree { | 5448 | impl std::fmt::Display for UseTree { |
5447 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5449 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5448 | std::fmt::Display::fmt(self.syntax(), f) | 5450 | std::fmt::Display::fmt(self.syntax(), f) |
5449 | } | 5451 | } |
5450 | } | 5452 | } |
5451 | impl std::fmt::Display for Alias { | 5453 | impl std::fmt::Display for Alias { |
5452 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5454 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5453 | std::fmt::Display::fmt(self.syntax(), f) | 5455 | std::fmt::Display::fmt(self.syntax(), f) |
5454 | } | 5456 | } |
5455 | } | 5457 | } |
5456 | impl std::fmt::Display for UseTreeList { | 5458 | impl std::fmt::Display for UseTreeList { |
5457 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5459 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5458 | std::fmt::Display::fmt(self.syntax(), f) | 5460 | std::fmt::Display::fmt(self.syntax(), f) |
5459 | } | 5461 | } |
5460 | } | 5462 | } |
5461 | impl std::fmt::Display for ExternCrateItem { | 5463 | impl std::fmt::Display for ExternCrateItem { |
5462 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5464 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5463 | std::fmt::Display::fmt(self.syntax(), f) | 5465 | std::fmt::Display::fmt(self.syntax(), f) |
5464 | } | 5466 | } |
5465 | } | 5467 | } |
5466 | impl std::fmt::Display for ArgList { | 5468 | impl std::fmt::Display for ArgList { |
5467 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5469 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5468 | std::fmt::Display::fmt(self.syntax(), f) | 5470 | std::fmt::Display::fmt(self.syntax(), f) |
5469 | } | 5471 | } |
5470 | } | 5472 | } |
5471 | impl std::fmt::Display for Path { | 5473 | impl std::fmt::Display for Path { |
5472 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5474 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5473 | std::fmt::Display::fmt(self.syntax(), f) | 5475 | std::fmt::Display::fmt(self.syntax(), f) |
5474 | } | 5476 | } |
5475 | } | 5477 | } |
5476 | impl std::fmt::Display for PathSegment { | 5478 | impl std::fmt::Display for PathSegment { |
5477 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5479 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5478 | std::fmt::Display::fmt(self.syntax(), f) | 5480 | std::fmt::Display::fmt(self.syntax(), f) |
5479 | } | 5481 | } |
5480 | } | 5482 | } |
5481 | impl std::fmt::Display for TypeArgList { | 5483 | impl std::fmt::Display for TypeArgList { |
5482 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5484 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5483 | std::fmt::Display::fmt(self.syntax(), f) | 5485 | std::fmt::Display::fmt(self.syntax(), f) |
5484 | } | 5486 | } |
5485 | } | 5487 | } |
5486 | impl std::fmt::Display for TypeArg { | 5488 | impl std::fmt::Display for TypeArg { |
5487 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5489 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5488 | std::fmt::Display::fmt(self.syntax(), f) | 5490 | std::fmt::Display::fmt(self.syntax(), f) |
5489 | } | 5491 | } |
5490 | } | 5492 | } |
5491 | impl std::fmt::Display for AssocTypeArg { | 5493 | impl std::fmt::Display for AssocTypeArg { |
5492 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5494 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5493 | std::fmt::Display::fmt(self.syntax(), f) | 5495 | std::fmt::Display::fmt(self.syntax(), f) |
5494 | } | 5496 | } |
5495 | } | 5497 | } |
5496 | impl std::fmt::Display for LifetimeArg { | 5498 | impl std::fmt::Display for LifetimeArg { |
5497 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5499 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5498 | std::fmt::Display::fmt(self.syntax(), f) | 5500 | std::fmt::Display::fmt(self.syntax(), f) |
5499 | } | 5501 | } |
5500 | } | 5502 | } |
5501 | impl std::fmt::Display for ConstArg { | 5503 | impl std::fmt::Display for ConstArg { |
5502 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5504 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5503 | std::fmt::Display::fmt(self.syntax(), f) | 5505 | std::fmt::Display::fmt(self.syntax(), f) |
5504 | } | 5506 | } |
5505 | } | 5507 | } |
5506 | impl std::fmt::Display for MacroItems { | 5508 | impl std::fmt::Display for MacroItems { |
5507 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5509 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5508 | std::fmt::Display::fmt(self.syntax(), f) | 5510 | std::fmt::Display::fmt(self.syntax(), f) |
5509 | } | 5511 | } |
5510 | } | 5512 | } |
5511 | impl std::fmt::Display for MacroStmts { | 5513 | impl std::fmt::Display for MacroStmts { |
5512 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5514 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5513 | std::fmt::Display::fmt(self.syntax(), f) | 5515 | std::fmt::Display::fmt(self.syntax(), f) |
5514 | } | 5516 | } |
5515 | } | 5517 | } |
5516 | impl std::fmt::Display for ExternItemList { | 5518 | impl std::fmt::Display for ExternItemList { |
5517 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5519 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5518 | std::fmt::Display::fmt(self.syntax(), f) | 5520 | std::fmt::Display::fmt(self.syntax(), f) |
5519 | } | 5521 | } |
5520 | } | 5522 | } |
5521 | impl std::fmt::Display for ExternBlock { | 5523 | impl std::fmt::Display for ExternBlock { |
5522 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5524 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5523 | std::fmt::Display::fmt(self.syntax(), f) | 5525 | std::fmt::Display::fmt(self.syntax(), f) |
5524 | } | 5526 | } |
5525 | } | 5527 | } |
5526 | impl std::fmt::Display for MetaItem { | 5528 | impl std::fmt::Display for MetaItem { |
5527 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5529 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5528 | std::fmt::Display::fmt(self.syntax(), f) | 5530 | std::fmt::Display::fmt(self.syntax(), f) |
5529 | } | 5531 | } |
5530 | } | 5532 | } |
5531 | impl std::fmt::Display for MacroDef { | 5533 | impl std::fmt::Display for MacroDef { |
5532 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 5534 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
5533 | std::fmt::Display::fmt(self.syntax(), f) | 5535 | std::fmt::Display::fmt(self.syntax(), f) |
5534 | } | 5536 | } |
5535 | } | 5537 | } |
diff --git a/crates/ra_syntax/src/ast/generated/tokens.rs b/crates/ra_syntax/src/ast/generated/tokens.rs index f91befaac..abadd0b61 100644 --- a/crates/ra_syntax/src/ast/generated/tokens.rs +++ b/crates/ra_syntax/src/ast/generated/tokens.rs | |||
@@ -11,7 +11,7 @@ pub struct Whitespace { | |||
11 | pub(crate) syntax: SyntaxToken, | 11 | pub(crate) syntax: SyntaxToken, |
12 | } | 12 | } |
13 | impl std::fmt::Display for Whitespace { | 13 | impl std::fmt::Display for Whitespace { |
14 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 14 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
15 | std::fmt::Display::fmt(&self.syntax, f) | 15 | std::fmt::Display::fmt(&self.syntax, f) |
16 | } | 16 | } |
17 | } | 17 | } |
@@ -32,7 +32,7 @@ pub struct Comment { | |||
32 | pub(crate) syntax: SyntaxToken, | 32 | pub(crate) syntax: SyntaxToken, |
33 | } | 33 | } |
34 | impl std::fmt::Display for Comment { | 34 | impl std::fmt::Display for Comment { |
35 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 35 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
36 | std::fmt::Display::fmt(&self.syntax, f) | 36 | std::fmt::Display::fmt(&self.syntax, f) |
37 | } | 37 | } |
38 | } | 38 | } |
@@ -53,7 +53,7 @@ pub struct String { | |||
53 | pub(crate) syntax: SyntaxToken, | 53 | pub(crate) syntax: SyntaxToken, |
54 | } | 54 | } |
55 | impl std::fmt::Display for String { | 55 | impl std::fmt::Display for String { |
56 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 56 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
57 | std::fmt::Display::fmt(&self.syntax, f) | 57 | std::fmt::Display::fmt(&self.syntax, f) |
58 | } | 58 | } |
59 | } | 59 | } |
@@ -74,7 +74,7 @@ pub struct RawString { | |||
74 | pub(crate) syntax: SyntaxToken, | 74 | pub(crate) syntax: SyntaxToken, |
75 | } | 75 | } |
76 | impl std::fmt::Display for RawString { | 76 | impl std::fmt::Display for RawString { |
77 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 77 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
78 | std::fmt::Display::fmt(&self.syntax, f) | 78 | std::fmt::Display::fmt(&self.syntax, f) |
79 | } | 79 | } |
80 | } | 80 | } |
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 3cd6d99c3..2e72d4927 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -84,7 +84,7 @@ impl Whitespace { | |||
84 | } | 84 | } |
85 | 85 | ||
86 | pub struct QuoteOffsets { | 86 | pub struct QuoteOffsets { |
87 | pub quotes: [TextRange; 2], | 87 | pub quotes: (TextRange, TextRange), |
88 | pub contents: TextRange, | 88 | pub contents: TextRange, |
89 | } | 89 | } |
90 | 90 | ||
@@ -103,7 +103,7 @@ impl QuoteOffsets { | |||
103 | let end = TextSize::of(literal); | 103 | let end = TextSize::of(literal); |
104 | 104 | ||
105 | let res = QuoteOffsets { | 105 | let res = QuoteOffsets { |
106 | quotes: [TextRange::new(start, left_quote), TextRange::new(right_quote, end)], | 106 | quotes: (TextRange::new(start, left_quote), TextRange::new(right_quote, end)), |
107 | contents: TextRange::new(left_quote, right_quote), | 107 | contents: TextRange::new(left_quote, right_quote), |
108 | }; | 108 | }; |
109 | Some(res) | 109 | Some(res) |
@@ -116,17 +116,17 @@ pub trait HasQuotes: AstToken { | |||
116 | let offsets = QuoteOffsets::new(text)?; | 116 | let offsets = QuoteOffsets::new(text)?; |
117 | let o = self.syntax().text_range().start(); | 117 | let o = self.syntax().text_range().start(); |
118 | let offsets = QuoteOffsets { | 118 | let offsets = QuoteOffsets { |
119 | quotes: [offsets.quotes[0] + o, offsets.quotes[1] + o], | 119 | quotes: (offsets.quotes.0 + o, offsets.quotes.1 + o), |
120 | contents: offsets.contents + o, | 120 | contents: offsets.contents + o, |
121 | }; | 121 | }; |
122 | Some(offsets) | 122 | Some(offsets) |
123 | } | 123 | } |
124 | fn open_quote_text_range(&self) -> Option<TextRange> { | 124 | fn open_quote_text_range(&self) -> Option<TextRange> { |
125 | self.quote_offsets().map(|it| it.quotes[0]) | 125 | self.quote_offsets().map(|it| it.quotes.0) |
126 | } | 126 | } |
127 | 127 | ||
128 | fn close_quote_text_range(&self) -> Option<TextRange> { | 128 | fn close_quote_text_range(&self) -> Option<TextRange> { |
129 | self.quote_offsets().map(|it| it.quotes[1]) | 129 | self.quote_offsets().map(|it| it.quotes.1) |
130 | } | 130 | } |
131 | 131 | ||
132 | fn text_range_between_quotes(&self) -> Option<TextRange> { | 132 | fn text_range_between_quotes(&self) -> Option<TextRange> { |
@@ -335,16 +335,26 @@ pub trait HasFormatSpecifier: AstToken { | |||
335 | } | 335 | } |
336 | c if c == '_' || c.is_alphabetic() => { | 336 | c if c == '_' || c.is_alphabetic() => { |
337 | read_identifier(&mut chars, &mut callback); | 337 | read_identifier(&mut chars, &mut callback); |
338 | if chars.peek().and_then(|next| next.1.as_ref().ok()).copied() | 338 | // can be either width (indicated by dollar sign, or type in which case |
339 | != Some('$') | 339 | // the next sign has to be `}`) |
340 | { | 340 | let next = |
341 | continue; | 341 | chars.peek().and_then(|next| next.1.as_ref().ok()).copied(); |
342 | } | 342 | match next { |
343 | skip_char_and_emit( | 343 | Some('$') => skip_char_and_emit( |
344 | &mut chars, | 344 | &mut chars, |
345 | FormatSpecifier::DollarSign, | 345 | FormatSpecifier::DollarSign, |
346 | &mut callback, | 346 | &mut callback, |
347 | ); | 347 | ), |
348 | Some('}') => { | ||
349 | skip_char_and_emit( | ||
350 | &mut chars, | ||
351 | FormatSpecifier::Close, | ||
352 | &mut callback, | ||
353 | ); | ||
354 | continue; | ||
355 | } | ||
356 | _ => continue, | ||
357 | }; | ||
348 | } | 358 | } |
349 | _ => {} | 359 | _ => {} |
350 | } | 360 | } |
@@ -416,17 +426,11 @@ pub trait HasFormatSpecifier: AstToken { | |||
416 | } | 426 | } |
417 | } | 427 | } |
418 | 428 | ||
419 | let mut cloned = chars.clone().take(2); | 429 | if let Some((_, Ok('}'))) = chars.peek() { |
420 | let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); | 430 | skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); |
421 | let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied(); | 431 | } else { |
422 | if first != Some('}') { | ||
423 | continue; | ||
424 | } | ||
425 | if second == Some('}') { | ||
426 | // Escaped format end specifier, `}}` | ||
427 | continue; | 432 | continue; |
428 | } | 433 | } |
429 | skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); | ||
430 | } | 434 | } |
431 | _ => { | 435 | _ => { |
432 | while let Some((_, Ok(next_char))) = chars.peek() { | 436 | while let Some((_, Ok(next_char))) = chars.peek() { |
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index bfc05e08b..a8f2454fd 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -83,13 +83,22 @@ pub trait DocCommentsOwner: AstNode { | |||
83 | CommentIter { iter: self.syntax().children_with_tokens() } | 83 | CommentIter { iter: self.syntax().children_with_tokens() } |
84 | } | 84 | } |
85 | 85 | ||
86 | fn doc_comment_text(&self) -> Option<String> { | ||
87 | self.doc_comments().doc_comment_text() | ||
88 | } | ||
89 | } | ||
90 | |||
91 | impl CommentIter { | ||
92 | pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> CommentIter { | ||
93 | CommentIter { iter: syntax_node.children_with_tokens() } | ||
94 | } | ||
95 | |||
86 | /// Returns the textual content of a doc comment block as a single string. | 96 | /// Returns the textual content of a doc comment block as a single string. |
87 | /// That is, strips leading `///` (+ optional 1 character of whitespace), | 97 | /// That is, strips leading `///` (+ optional 1 character of whitespace), |
88 | /// trailing `*/`, trailing whitespace and then joins the lines. | 98 | /// trailing `*/`, trailing whitespace and then joins the lines. |
89 | fn doc_comment_text(&self) -> Option<String> { | 99 | pub fn doc_comment_text(self) -> Option<String> { |
90 | let mut has_comments = false; | 100 | let mut has_comments = false; |
91 | let docs = self | 101 | let docs = self |
92 | .doc_comments() | ||
93 | .filter(|comment| comment.kind().doc.is_some()) | 102 | .filter(|comment| comment.kind().doc.is_some()) |
94 | .map(|comment| { | 103 | .map(|comment| { |
95 | has_comments = true; | 104 | has_comments = true; |
diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast index 7c957fdde..48610a5eb 100644 --- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast +++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast | |||
@@ -180,44 +180,45 @@ [email protected] | |||
180 | [email protected] | 180 | [email protected] |
181 | [email protected] | 181 | [email protected] |
182 | [email protected] "(" | 182 | [email protected] "(" |
183 | [email protected] | 183 | [email protected] |
184 | [email protected] | 184 | [email protected] "for" |
185 | [email protected] | 185 | [email protected] |
186 | [email protected] | 186 | [email protected] |
187 | [email protected] | 187 | [email protected] |
188 | [email protected] | 188 | [email protected] "<" |
189 | [email protected] "for" | 189 | [email protected] |
190 | [email protected] | 190 | [email protected] "\'a" |
191 | [email protected] "<" | 191 | [email protected] ">" |
192 | [email protected] | 192 | [email protected] " " |
193 | [email protected] "\'a" | 193 | [email protected] |
194 | [email protected] ">" | 194 | [email protected] |
195 | [email protected] " " | 195 | [email protected] |
196 | [email protected] | ||
196 | [email protected] | 197 | [email protected] |
197 | [email protected] | 198 | [email protected] |
198 | [email protected] | 199 | [email protected] |
199 | [email protected] | 200 | [email protected] |
200 | [email protected] "Trait" | 201 | [email protected] "Trait" |
201 | [email protected] "<" | 202 | [email protected] "<" |
202 | [email protected] | 203 | [email protected] |
203 | [email protected] "\'a" | 204 | [email protected] "\'a" |
204 | [email protected] ">" | 205 | [email protected] ">" |
205 | [email protected] | 206 | [email protected] |
206 | [email protected] ")" | 207 | [email protected] ")" |
207 | [email protected] " " | 208 | [email protected] " " |
208 | [email protected] "+" | 209 | [email protected] "+" |
209 | [email protected] " " | 210 | [email protected] " " |
210 | [email protected] | 211 | [email protected] |
211 | [email protected] "(" | 212 | [email protected] "(" |
212 | [email protected] | 213 | [email protected] |
213 | [email protected] | 214 | [email protected] |
214 | [email protected] | 215 | [email protected] |
215 | [email protected] | 216 | [email protected] |
216 | [email protected] "Copy" | 217 | [email protected] "Copy" |
217 | [email protected] ")" | 218 | [email protected] ")" |
218 | [email protected] ">" | 219 | [email protected] ">" |
219 | [email protected] | 220 | [email protected] |
220 | [email protected] ";" | 221 | [email protected] ";" |
221 | [email protected] "\n " | 222 | [email protected] "\n " |
222 | [email protected] | 223 | [email protected] |
223 | [email protected] "let" | 224 | [email protected] "let" |
@@ -302,13 +303,12 @@ error 146..146: expected expression | |||
302 | error 147..147: expected SEMICOLON | 303 | error 147..147: expected SEMICOLON |
303 | error 148..148: expected expression | 304 | error 148..148: expected expression |
304 | error 149..149: expected SEMICOLON | 305 | error 149..149: expected SEMICOLON |
305 | error 154..154: expected pattern | 306 | error 155..155: expected type |
306 | error 155..155: expected IN_KW | 307 | error 158..158: expected IN_KW |
307 | error 155..155: expected expression | ||
308 | error 157..157: expected a block | ||
309 | error 165..165: expected expression | 308 | error 165..165: expected expression |
310 | error 168..168: expected expression | 309 | error 168..168: expected expression |
311 | error 179..179: expected expression | 310 | error 179..179: expected expression |
311 | error 180..180: expected a block | ||
312 | error 180..180: expected COMMA | 312 | error 180..180: expected COMMA |
313 | error 180..180: expected expression | 313 | error 180..180: expected expression |
314 | error 180..180: expected R_PAREN | 314 | error 180..180: expected R_PAREN |
diff --git a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast index 568a4cc02..4d6461d1e 100644 --- a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast +++ b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast | |||
@@ -12,17 +12,16 @@ [email protected] | |||
12 | [email protected] "where" | 12 | [email protected] "where" |
13 | [email protected] " " | 13 | [email protected] " " |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] "for" |
16 | [email protected] "for" | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] "<" |
18 | [email protected] "<" | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] "\'a" |
20 | [email protected] "\'a" | 20 | [email protected] ">" |
21 | [email protected] ">" | ||
22 | [email protected] "\n" | 21 | [email protected] "\n" |
23 | [email protected] | 22 | [email protected] |
24 | [email protected] "{" | 23 | [email protected] "{" |
25 | [email protected] "}" | 24 | [email protected] "}" |
26 | [email protected] "\n" | 25 | [email protected] "\n" |
27 | error 26..26: expected a path | 26 | error 26..26: expected type |
28 | error 26..26: expected colon | 27 | error 26..26: expected colon |
diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast new file mode 100644 index 000000000..8eb583ef8 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast | |||
@@ -0,0 +1,40 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "trait" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "T" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] "\n " | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "default" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] "const" | ||
19 | [email protected] " " | ||
20 | [email protected] | ||
21 | [email protected] "f" | ||
22 | [email protected] ":" | ||
23 | [email protected] " " | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] "u8" | ||
29 | [email protected] " " | ||
30 | [email protected] "=" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] "0" | ||
34 | [email protected] ";" | ||
35 | [email protected] "\n" | ||
36 | [email protected] "}" | ||
37 | [email protected] "\n" | ||
38 | error 19..19: expected BANG | ||
39 | error 19..19: expected `{`, `[`, `(` | ||
40 | error 19..19: expected SEMICOLON | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rs b/crates/ra_syntax/test_data/parser/err/0043_default_const.rs new file mode 100644 index 000000000..80f15474a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0043_default_const.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | trait T { | ||
2 | default const f: u8 = 0; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast new file mode 100644 index 000000000..cb90f28bc --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast | |||
@@ -0,0 +1,240 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "ForRef" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "for" | ||
12 | [email protected] | ||
13 | [email protected] "<" | ||
14 | [email protected] | ||
15 | [email protected] "\'a" | ||
16 | [email protected] ">" | ||
17 | [email protected] " " | ||
18 | [email protected] | ||
19 | [email protected] "&" | ||
20 | [email protected] "\'a" | ||
21 | [email protected] " " | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] "u32" | ||
27 | [email protected] ";" | ||
28 | [email protected] "\n" | ||
29 | [email protected] | ||
30 | [email protected] "type" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] "ForTup" | ||
34 | [email protected] " " | ||
35 | [email protected] "=" | ||
36 | [email protected] " " | ||
37 | [email protected] | ||
38 | [email protected] "for" | ||
39 | [email protected] | ||
40 | [email protected] "<" | ||
41 | [email protected] | ||
42 | [email protected] "\'a" | ||
43 | [email protected] ">" | ||
44 | [email protected] " " | ||
45 | [email protected] | ||
46 | [email protected] "(" | ||
47 | [email protected] | ||
48 | [email protected] "&" | ||
49 | [email protected] "\'a" | ||
50 | [email protected] " " | ||
51 | [email protected] | ||
52 | [email protected] | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] "u32" | ||
56 | [email protected] "," | ||
57 | [email protected] ")" | ||
58 | [email protected] ";" | ||
59 | [email protected] "\n" | ||
60 | [email protected] | ||
61 | [email protected] "type" | ||
62 | [email protected] " " | ||
63 | [email protected] | ||
64 | [email protected] "ForSlice" | ||
65 | [email protected] " " | ||
66 | [email protected] "=" | ||
67 | [email protected] " " | ||
68 | [email protected] | ||
69 | [email protected] "for" | ||
70 | [email protected] | ||
71 | [email protected] "<" | ||
72 | [email protected] | ||
73 | [email protected] "\'a" | ||
74 | [email protected] ">" | ||
75 | [email protected] " " | ||
76 | [email protected] | ||
77 | [email protected] "[" | ||
78 | [email protected] | ||
79 | [email protected] | ||
80 | [email protected] | ||
81 | [email protected] | ||
82 | [email protected] "u32" | ||
83 | [email protected] "]" | ||
84 | [email protected] ";" | ||
85 | [email protected] "\n" | ||
86 | [email protected] | ||
87 | [email protected] "type" | ||
88 | [email protected] " " | ||
89 | [email protected] | ||
90 | [email protected] "ForForFn" | ||
91 | [email protected] " " | ||
92 | [email protected] "=" | ||
93 | [email protected] " " | ||
94 | [email protected] | ||
95 | [email protected] "for" | ||
96 | [email protected] | ||
97 | [email protected] "<" | ||
98 | [email protected] | ||
99 | [email protected] "\'a" | ||
100 | [email protected] ">" | ||
101 | [email protected] " " | ||
102 | [email protected] | ||
103 | [email protected] "for" | ||
104 | [email protected] | ||
105 | [email protected] "<" | ||
106 | [email protected] | ||
107 | [email protected] "\'b" | ||
108 | [email protected] ">" | ||
109 | [email protected] " " | ||
110 | [email protected] | ||
111 | [email protected] "fn" | ||
112 | [email protected] | ||
113 | [email protected] "(" | ||
114 | [email protected] | ||
115 | [email protected] | ||
116 | [email protected] "&" | ||
117 | [email protected] "\'a" | ||
118 | [email protected] " " | ||
119 | [email protected] | ||
120 | [email protected] | ||
121 | [email protected] | ||
122 | [email protected] | ||
123 | [email protected] "i32" | ||
124 | [email protected] "," | ||
125 | [email protected] " " | ||
126 | [email protected] | ||
127 | [email protected] | ||
128 | [email protected] "&" | ||
129 | [email protected] "\'b" | ||
130 | [email protected] " " | ||
131 | [email protected] | ||
132 | [email protected] | ||
133 | [email protected] | ||
134 | [email protected] | ||
135 | [email protected] "i32" | ||
136 | [email protected] ")" | ||
137 | [email protected] ";" | ||
138 | [email protected] "\n" | ||
139 | [email protected] | ||
140 | [email protected] "fn" | ||
141 | [email protected] " " | ||
142 | [email protected] | ||
143 | [email protected] "for_for_for" | ||
144 | [email protected] | ||
145 | [email protected] "<" | ||
146 | [email protected] | ||
147 | [email protected] | ||
148 | [email protected] "T" | ||
149 | [email protected] ">" | ||
150 | [email protected] | ||
151 | [email protected] "(" | ||
152 | [email protected] ")" | ||
153 | [email protected] "\n" | ||
154 | [email protected] | ||
155 | [email protected] "where" | ||
156 | [email protected] "\n " | ||
157 | [email protected] | ||
158 | [email protected] "for" | ||
159 | [email protected] | ||
160 | [email protected] "<" | ||
161 | [email protected] | ||
162 | [email protected] "\'a" | ||
163 | [email protected] ">" | ||
164 | [email protected] " " | ||
165 | [email protected] | ||
166 | [email protected] "for" | ||
167 | [email protected] | ||
168 | [email protected] "<" | ||
169 | [email protected] | ||
170 | [email protected] "\'b" | ||
171 | [email protected] ">" | ||
172 | [email protected] " " | ||
173 | [email protected] | ||
174 | [email protected] "for" | ||
175 | [email protected] | ||
176 | [email protected] "<" | ||
177 | [email protected] | ||
178 | [email protected] "\'c" | ||
179 | [email protected] ">" | ||
180 | [email protected] " " | ||
181 | [email protected] | ||
182 | [email protected] "fn" | ||
183 | [email protected] | ||
184 | [email protected] "(" | ||
185 | [email protected] | ||
186 | [email protected] | ||
187 | [email protected] "&" | ||
188 | [email protected] "\'a" | ||
189 | [email protected] " " | ||
190 | [email protected] | ||
191 | [email protected] | ||
192 | [email protected] | ||
193 | [email protected] | ||
194 | [email protected] "T" | ||
195 | [email protected] "," | ||
196 | [email protected] " " | ||
197 | [email protected] | ||
198 | [email protected] | ||
199 | [email protected] "&" | ||
200 | [email protected] "\'b" | ||
201 | [email protected] " " | ||
202 | [email protected] | ||
203 | [email protected] | ||
204 | [email protected] | ||
205 | [email protected] | ||
206 | [email protected] "T" | ||
207 | [email protected] "," | ||
208 | [email protected] " " | ||
209 | [email protected] | ||
210 | [email protected] | ||
211 | [email protected] "&" | ||
212 | [email protected] "\'c" | ||
213 | [email protected] " " | ||
214 | [email protected] | ||
215 | [email protected] | ||
216 | [email protected] | ||
217 | [email protected] | ||
218 | [email protected] "T" | ||
219 | [email protected] ")" | ||
220 | [email protected] ":" | ||
221 | [email protected] " " | ||
222 | [email protected] | ||
223 | [email protected] | ||
224 | [email protected] | ||
225 | [email protected] | ||
226 | [email protected] | ||
227 | [email protected] | ||
228 | [email protected] "Copy" | ||
229 | [email protected] "," | ||
230 | [email protected] "\n" | ||
231 | [email protected] | ||
232 | [email protected] "{" | ||
233 | [email protected] "\n" | ||
234 | [email protected] "}" | ||
235 | [email protected] "\n" | ||
236 | error 21..21: expected a function pointer or path | ||
237 | error 52..52: expected a function pointer or path | ||
238 | error 88..88: expected a function pointer or path | ||
239 | error 119..119: expected a function pointer or path | ||
240 | error 195..195: expected a function pointer or path | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs new file mode 100644 index 000000000..0e9f8ccb4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rs | |||
@@ -0,0 +1,9 @@ | |||
1 | type ForRef = for<'a> &'a u32; | ||
2 | type ForTup = for<'a> (&'a u32,); | ||
3 | type ForSlice = for<'a> [u32]; | ||
4 | type ForForFn = for<'a> for<'b> fn(&'a i32, &'b i32); | ||
5 | fn for_for_for<T>() | ||
6 | where | ||
7 | for<'a> for<'b> for<'c> fn(&'a T, &'b T, &'c T): Copy, | ||
8 | { | ||
9 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast index 9be441110..53f7ebaf9 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast +++ b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast | |||
@@ -17,23 +17,29 @@ [email protected] | |||
17 | [email protected] "{" | 17 | [email protected] "{" |
18 | [email protected] "}" | 18 | [email protected] "}" |
19 | [email protected] "\n" | 19 | [email protected] "\n" |
20 | ERROR@25..31 | 20 | CONST_DEF@25..46 |
21 | [email protected] "unsafe" | 21 | [email protected] "unsafe" |
22 | [email protected] " " | 22 | [email protected] " " |
23 | [email protected] | ||
24 | [email protected] "const" | 23 | [email protected] "const" |
25 | [email protected] " " | 24 | [email protected] " " |
26 | [email protected] "fn" | 25 | [email protected] |
26 | [email protected] "fn" | ||
27 | [email protected] " " | 27 | [email protected] " " |
28 | [email protected] | 28 | [email protected] |
29 | [email protected] "bar" | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "(" | 31 | [email protected] |
32 | [email protected] ")" | 32 | [email protected] "bar" |
33 | [email protected] " " | 33 | [email protected] |
34 | [email protected] | 34 | [email protected] "(" |
35 | [email protected] "{" | 35 | [email protected] ")" |
36 | [email protected] "}" | 36 | [email protected] " " |
37 | [email protected] | ||
38 | [email protected] "{" | ||
39 | [email protected] "}" | ||
37 | [email protected] "\n" | 40 | [email protected] "\n" |
38 | error 6..6: expected existential, fn, trait or impl | 41 | error 6..6: expected existential, fn, trait or impl |
39 | error 31..31: expected existential, fn, trait or impl | 42 | error 38..38: expected a name |
43 | error 40..40: expected COLON | ||
44 | error 46..46: expected SEMICOLON | ||
45 | error 47..47: expected an item | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast index 9dc473e43..cd0892451 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast | |||
@@ -1,61 +1,60 @@ | |||
1 | [email protected]9 | 1 | SOURCE_FILE@0..54 |
2 | FN_DEF@0..48 | 2 | FN_DEF@0..53 |
3 | [email protected] "fn" | 3 | [email protected] "fn" |
4 | [email protected] " " | 4 | [email protected] " " |
5 | [email protected] | 5 | [email protected] |
6 | [email protected] "test" | 6 | [email protected] "for_trait" |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "<" | 8 | [email protected] "<" |
9 | [email protected] | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "F" | 11 | [email protected] "F" |
12 | [email protected] ">" | 12 | [email protected] ">" |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] "(" | 14 | [email protected] "(" |
15 | [email protected] ")" | 15 | [email protected] ")" |
16 | [email protected] "\n" | 16 | [email protected] "\n" |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "where" | 18 | [email protected] "where" |
19 | [email protected] "\n " | 19 | [email protected] "\n " |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] | 21 | [email protected] "for" |
22 | [email protected] "for" | 22 | [email protected] |
23 | [email protected] | 23 | [email protected] "<" |
24 | [email protected] "<" | 24 | [email protected] |
25 | [email protected] | 25 | [email protected] "\'a" |
26 | [email protected] "\'a" | 26 | [email protected] ">" |
27 | [email protected] ">" | 27 | [email protected] " " |
28 | [email protected] " " | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] | 31 | [email protected] |
32 | [email protected] | 32 | [email protected] "F" |
33 | [email protected] "F" | 33 | [email protected] ":" |
34 | [email protected] ":" | 34 | [email protected] " " |
35 | [email protected] " " | 35 | [email protected] |
36 | [email protected] | 36 | [email protected] |
37 | [email protected] | 37 | [email protected] |
38 | [email protected] | 38 | [email protected] |
39 | [email protected] | 39 | [email protected] |
40 | [email protected] | 40 | [email protected] |
41 | [email protected] | 41 | [email protected] "Fn" |
42 | [email protected] "Fn" | 42 | [email protected] |
43 | [email protected] | 43 | [email protected] "(" |
44 | [email protected] "(" | 44 | [email protected] |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] | 46 | [email protected] "&" |
47 | [email protected] "&" | 47 | [email protected] "\'a" |
48 | [email protected] "\'a" | 48 | [email protected] " " |
49 | [email protected] " " | 49 | [email protected] |
50 | [email protected] | 50 | [email protected] |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] | 52 | [email protected] |
53 | [email protected] | 53 | [email protected] "str" |
54 | [email protected] "str" | 54 | [email protected] ")" |
55 | [email protected] ")" | 55 | [email protected] "\n" |
56 | [email protected] "\n" | 56 | [email protected] |
57 | [email protected] | 57 | [email protected] "{" |
58 | [email protected] "{" | 58 | [email protected] " " |
59 | [email protected] " " | 59 | [email protected] "}" |
60 | [email protected] "}" | 60 | [email protected] "\n" |
61 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs index b448c6178..423bc105b 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | fn test<F>() | 1 | fn for_trait<F>() |
2 | where | 2 | where |
3 | for<'a> F: Fn(&'a str) | 3 | for<'a> F: Fn(&'a str) |
4 | { } | 4 | { } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast index dfb8d57ad..b26ac2d36 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast | |||
@@ -1,4 +1,4 @@ | |||
1 | [email protected]00 | 1 | SOURCE_FILE@0..121 |
2 | [email protected] | 2 | [email protected] |
3 | [email protected] "type" | 3 | [email protected] "type" |
4 | [email protected] " " | 4 | [email protected] " " |
@@ -29,212 +29,84 @@ [email protected] | |||
29 | [email protected] ")" | 29 | [email protected] ")" |
30 | [email protected] ";" | 30 | [email protected] ";" |
31 | [email protected] "\n" | 31 | [email protected] "\n" |
32 | [email protected] | 32 | [email protected] |
33 | [email protected] "fn" | 33 | [email protected] "type" |
34 | [email protected] " " | 34 | [email protected] " " |
35 | [email protected] | 35 | [email protected] |
36 | [email protected] "foo" | 36 | [email protected] "B" |
37 | [email protected] | 37 | [email protected] " " |
38 | [email protected] "<" | 38 | [email protected] "=" |
39 | [email protected] | 39 | [email protected] " " |
40 | [email protected] | 40 | [email protected] |
41 | [email protected] "T" | 41 | [email protected] "for" |
42 | [email protected] ">" | 42 | [email protected] |
43 | [email protected] | 43 | [email protected] "<" |
44 | [email protected] "(" | 44 | [email protected] |
45 | [email protected] | 45 | [email protected] "\'a" |
46 | [email protected] | 46 | [email protected] ">" |
47 | [email protected] | 47 | [email protected] " " |
48 | [email protected] "_t" | 48 | [email protected] |
49 | [email protected] ":" | 49 | [email protected] "unsafe" |
50 | [email protected] " " | 50 | [email protected] " " |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] "&" | 52 | [email protected] "extern" |
53 | [email protected] | 53 | [email protected] " " |
54 | [email protected] | 54 | [email protected] "\"C\"" |
55 | [email protected] | 55 | [email protected] " " |
56 | [email protected] | 56 | [email protected] "fn" |
57 | [email protected] "T" | 57 | [email protected] |
58 | [email protected] ")" | 58 | [email protected] "(" |
59 | [email protected] " " | 59 | [email protected] |
60 | [email protected] | 60 | [email protected] |
61 | [email protected] "where" | 61 | [email protected] "&" |
62 | [email protected] " " | 62 | [email protected] "\'a" |
63 | [email protected] | 63 | [email protected] " " |
64 | [email protected] | 64 | [email protected] |
65 | [email protected] "for" | 65 | [email protected] "(" |
66 | [email protected] | 66 | [email protected] ")" |
67 | [email protected] "<" | 67 | [email protected] ")" |
68 | [email protected] | 68 | [email protected] " " |
69 | [email protected] "\'a" | 69 | [email protected] |
70 | [email protected] ">" | 70 | [email protected] "->" |
71 | [email protected] " " | 71 | [email protected] " " |
72 | [email protected] | 72 | [email protected] |
73 | [email protected] "&" | 73 | [email protected] "(" |
74 | [email protected] "\'a" | 74 | [email protected] ")" |
75 | [email protected] " " | 75 | [email protected] ";" |
76 | [email protected] | 76 | [email protected] "\n" |
77 | [email protected] | 77 | [email protected] |
78 | [email protected] | 78 | [email protected] "type" |
79 | [email protected] | 79 | [email protected] " " |
80 | [email protected] "T" | 80 | [email protected] |
81 | [email protected] ":" | 81 | [email protected] "Obj" |
82 | [email protected] " " | 82 | [email protected] " " |
83 | [email protected] | 83 | [email protected] "=" |
84 | [email protected] | 84 | [email protected] " " |
85 | [email protected] | 85 | [email protected] |
86 | [email protected] | 86 | [email protected] "for" |
87 | [email protected] | 87 | [email protected] |
88 | [email protected] | 88 | [email protected] "<" |
89 | [email protected] "Iterator" | 89 | [email protected] |
90 | [email protected] " " | 90 | [email protected] "\'a" |
91 | [email protected] | 91 | [email protected] ">" |
92 | [email protected] "{" | 92 | [email protected] " " |
93 | [email protected] "}" | 93 | [email protected] |
94 | [email protected] "\n" | 94 | [email protected] |
95 | [email protected] | 95 | [email protected] |
96 | [email protected] "fn" | 96 | [email protected] |
97 | [email protected] " " | 97 | [email protected] "PartialEq" |
98 | [email protected] | 98 | [email protected] |
99 | [email protected] "bar" | 99 | [email protected] "<" |
100 | [email protected] | 100 | [email protected] |
101 | [email protected] "<" | 101 | [email protected] |
102 | [email protected] | 102 | [email protected] "&" |
103 | [email protected] | 103 | [email protected] "\'a" |
104 | [email protected] "T" | 104 | [email protected] " " |
105 | [email protected] ">" | 105 | [email protected] |
106 | [email protected] | 106 | [email protected] |
107 | [email protected] "(" | 107 | [email protected] |
108 | [email protected] | 108 | [email protected] |
109 | [email protected] | 109 | [email protected] "i32" |
110 | [email protected] | 110 | [email protected] ">" |
111 | [email protected] "_t" | 111 | [email protected] ";" |
112 | [email protected] ":" | 112 | [email protected] "\n" |
113 | [email protected] " " | ||
114 | [email protected] | ||
115 | [email protected] "&" | ||
116 | [email protected] | ||
117 | [email protected] | ||
118 | [email protected] | ||
119 | [email protected] | ||
120 | [email protected] "T" | ||
121 | [email protected] ")" | ||
122 | [email protected] " " | ||
123 | [email protected] | ||
124 | [email protected] "where" | ||
125 | [email protected] " " | ||
126 | [email protected] | ||
127 | [email protected] | ||
128 | [email protected] "for" | ||
129 | [email protected] | ||
130 | [email protected] "<" | ||
131 | [email protected] | ||
132 | [email protected] "\'a" | ||
133 | [email protected] ">" | ||
134 | [email protected] " " | ||
135 | [email protected] | ||
136 | [email protected] "&" | ||
137 | [email protected] "\'a" | ||
138 | [email protected] " " | ||
139 | [email protected] "mut" | ||
140 | [email protected] " " | ||
141 | [email protected] | ||
142 | [email protected] | ||
143 | [email protected] | ||
144 | [email protected] | ||
145 | [email protected] "T" | ||
146 | [email protected] ":" | ||
147 | [email protected] " " | ||
148 | [email protected] | ||
149 | [email protected] | ||
150 | [email protected] | ||
151 | [email protected] | ||
152 | [email protected] | ||
153 | [email protected] | ||
154 | [email protected] "Iterator" | ||
155 | [email protected] " " | ||
156 | [email protected] | ||
157 | [email protected] "{" | ||
158 | [email protected] "}" | ||
159 | [email protected] "\n" | ||
160 | [email protected] | ||
161 | [email protected] "fn" | ||
162 | [email protected] " " | ||
163 | [email protected] | ||
164 | [email protected] "baz" | ||
165 | [email protected] | ||
166 | [email protected] "<" | ||
167 | [email protected] | ||
168 | [email protected] | ||
169 | [email protected] "T" | ||
170 | [email protected] ">" | ||
171 | [email protected] | ||
172 | [email protected] "(" | ||
173 | [email protected] | ||
174 | [email protected] | ||
175 | [email protected] | ||
176 | [email protected] "_t" | ||
177 | [email protected] ":" | ||
178 | [email protected] " " | ||
179 | [email protected] | ||
180 | [email protected] "&" | ||
181 | [email protected] | ||
182 | [email protected] | ||
183 | [email protected] | ||
184 | [email protected] | ||
185 | [email protected] "T" | ||
186 | [email protected] ")" | ||
187 | [email protected] " " | ||
188 | [email protected] | ||
189 | [email protected] "where" | ||
190 | [email protected] " " | ||
191 | [email protected] | ||
192 | [email protected] | ||
193 | [email protected] "for" | ||
194 | [email protected] | ||
195 | [email protected] "<" | ||
196 | [email protected] | ||
197 | [email protected] "\'a" | ||
198 | [email protected] ">" | ||
199 | [email protected] " " | ||
200 | [email protected] | ||
201 | [email protected] | ||
202 | [email protected] | ||
203 | [email protected] | ||
204 | [email protected] "<" | ||
205 | [email protected] | ||
206 | [email protected] "&" | ||
207 | [email protected] "\'a" | ||
208 | [email protected] " " | ||
209 | [email protected] | ||
210 | [email protected] | ||
211 | [email protected] | ||
212 | [email protected] | ||
213 | [email protected] "T" | ||
214 | [email protected] " " | ||
215 | [email protected] "as" | ||
216 | [email protected] " " | ||
217 | [email protected] | ||
218 | [email protected] | ||
219 | [email protected] | ||
220 | [email protected] | ||
221 | [email protected] "Baz" | ||
222 | [email protected] ">" | ||
223 | [email protected] "::" | ||
224 | [email protected] | ||
225 | [email protected] | ||
226 | [email protected] "Foo" | ||
227 | [email protected] ":" | ||
228 | [email protected] " " | ||
229 | [email protected] | ||
230 | [email protected] | ||
231 | [email protected] | ||
232 | [email protected] | ||
233 | [email protected] | ||
234 | [email protected] | ||
235 | [email protected] "Iterator" | ||
236 | [email protected] " " | ||
237 | [email protected] | ||
238 | [email protected] "{" | ||
239 | [email protected] "}" | ||
240 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs index d6774d438..8ac7b9e10 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rs | |||
@@ -1,4 +1,3 @@ | |||
1 | type A = for<'a> fn() -> (); | 1 | type A = for<'a> fn() -> (); |
2 | fn foo<T>(_t: &T) where for<'a> &'a T: Iterator {} | 2 | type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); |
3 | fn bar<T>(_t: &T) where for<'a> &'a mut T: Iterator {} | 3 | type Obj = for<'a> PartialEq<&'a i32>; |
4 | fn baz<T>(_t: &T) where for<'a> <&'a T as Baz>::Foo: Iterator {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast new file mode 100644 index 000000000..adb6159f4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast | |||
@@ -0,0 +1,40 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "Foo" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "\n " | ||
22 | [email protected] | ||
23 | [email protected] "default" | ||
24 | [email protected] " " | ||
25 | [email protected] "unsafe" | ||
26 | [email protected] " " | ||
27 | [email protected] "fn" | ||
28 | [email protected] " " | ||
29 | [email protected] | ||
30 | [email protected] "foo" | ||
31 | [email protected] | ||
32 | [email protected] "(" | ||
33 | [email protected] ")" | ||
34 | [email protected] " " | ||
35 | [email protected] | ||
36 | [email protected] "{" | ||
37 | [email protected] "}" | ||
38 | [email protected] "\n" | ||
39 | [email protected] "}" | ||
40 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs new file mode 100644 index 000000000..12926cd8a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | impl T for Foo { | ||
2 | default unsafe fn foo() {} | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast new file mode 100644 index 000000000..a9eda5668 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast | |||
@@ -0,0 +1,18 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "default" | ||
4 | [email protected] " " | ||
5 | [email protected] "unsafe" | ||
6 | [email protected] " " | ||
7 | [email protected] "impl" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] "Foo" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "{" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs new file mode 100644 index 000000000..ba0998ff4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs | |||
@@ -0,0 +1 @@ | |||
default unsafe impl Foo {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast new file mode 100644 index 000000000..868899275 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast | |||
@@ -0,0 +1,38 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "main" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] "let" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "<" | ||
22 | [email protected] | ||
23 | [email protected] "_" | ||
24 | [email protected] ">" | ||
25 | [email protected] "::" | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] "Foo" | ||
29 | [email protected] " " | ||
30 | [email protected] "=" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] "(" | ||
34 | [email protected] ")" | ||
35 | [email protected] ";" | ||
36 | [email protected] " " | ||
37 | [email protected] "}" | ||
38 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs new file mode 100644 index 000000000..ebe26834d --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rs | |||
@@ -0,0 +1 @@ | |||
fn main() { let <_>::Foo = (); } | |||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast new file mode 100644 index 000000000..dab0247ee --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast | |||
@@ -0,0 +1,44 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "Foo" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "\n " | ||
22 | [email protected] | ||
23 | [email protected] "default" | ||
24 | [email protected] " " | ||
25 | [email protected] "const" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "f" | ||
29 | [email protected] ":" | ||
30 | [email protected] " " | ||
31 | [email protected] | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "u8" | ||
36 | [email protected] " " | ||
37 | [email protected] "=" | ||
38 | [email protected] " " | ||
39 | [email protected] | ||
40 | [email protected] "0" | ||
41 | [email protected] ";" | ||
42 | [email protected] "\n" | ||
43 | [email protected] "}" | ||
44 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs new file mode 100644 index 000000000..dfb3b92dc --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | impl T for Foo { | ||
2 | default const f: u8 = 0; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast new file mode 100644 index 000000000..503585103 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast | |||
@@ -0,0 +1,392 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "for_trait" | ||
7 | [email protected] | ||
8 | [email protected] "<" | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] "F" | ||
12 | [email protected] ">" | ||
13 | [email protected] | ||
14 | [email protected] "(" | ||
15 | [email protected] ")" | ||
16 | [email protected] "\n" | ||
17 | [email protected] | ||
18 | [email protected] "where" | ||
19 | [email protected] "\n " | ||
20 | [email protected] | ||
21 | [email protected] "for" | ||
22 | [email protected] | ||
23 | [email protected] "<" | ||
24 | [email protected] | ||
25 | [email protected] "\'a" | ||
26 | [email protected] ">" | ||
27 | [email protected] " " | ||
28 | [email protected] | ||
29 | [email protected] | ||
30 | [email protected] | ||
31 | [email protected] | ||
32 | [email protected] "F" | ||
33 | [email protected] ":" | ||
34 | [email protected] " " | ||
35 | [email protected] | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "Fn" | ||
42 | [email protected] | ||
43 | [email protected] "(" | ||
44 | [email protected] | ||
45 | [email protected] | ||
46 | [email protected] "&" | ||
47 | [email protected] "\'a" | ||
48 | [email protected] " " | ||
49 | [email protected] | ||
50 | [email protected] | ||
51 | [email protected] | ||
52 | [email protected] | ||
53 | [email protected] "str" | ||
54 | [email protected] ")" | ||
55 | [email protected] "," | ||
56 | [email protected] "\n" | ||
57 | [email protected] | ||
58 | [email protected] "{" | ||
59 | [email protected] "\n" | ||
60 | [email protected] "}" | ||
61 | [email protected] "\n" | ||
62 | [email protected] | ||
63 | [email protected] "fn" | ||
64 | [email protected] " " | ||
65 | [email protected] | ||
66 | [email protected] "for_ref" | ||
67 | [email protected] | ||
68 | [email protected] "<" | ||
69 | [email protected] | ||
70 | [email protected] | ||
71 | [email protected] "F" | ||
72 | [email protected] ">" | ||
73 | [email protected] | ||
74 | [email protected] "(" | ||
75 | [email protected] ")" | ||
76 | [email protected] "\n" | ||
77 | [email protected] | ||
78 | [email protected] "where" | ||
79 | [email protected] "\n " | ||
80 | [email protected] | ||
81 | [email protected] "for" | ||
82 | [email protected] | ||
83 | [email protected] "<" | ||
84 | [email protected] | ||
85 | [email protected] "\'a" | ||
86 | [email protected] ">" | ||
87 | [email protected] " " | ||
88 | [email protected] | ||
89 | [email protected] "&" | ||
90 | [email protected] "\'a" | ||
91 | [email protected] " " | ||
92 | [email protected] | ||
93 | [email protected] | ||
94 | [email protected] | ||
95 | [email protected] | ||
96 | [email protected] "F" | ||
97 | [email protected] ":" | ||
98 | [email protected] " " | ||
99 | [email protected] | ||
100 | [email protected] | ||
101 | [email protected] | ||
102 | [email protected] | ||
103 | [email protected] | ||
104 | [email protected] | ||
105 | [email protected] "Debug" | ||
106 | [email protected] "," | ||
107 | [email protected] "\n" | ||
108 | [email protected] | ||
109 | [email protected] "{" | ||
110 | [email protected] "\n" | ||
111 | [email protected] "}" | ||
112 | [email protected] "\n" | ||
113 | [email protected] | ||
114 | [email protected] "fn" | ||
115 | [email protected] " " | ||
116 | [email protected] | ||
117 | [email protected] "for_parens" | ||
118 | [email protected] | ||
119 | [email protected] "<" | ||
120 | [email protected] | ||
121 | [email protected] | ||
122 | [email protected] "F" | ||
123 | [email protected] ">" | ||
124 | [email protected] | ||
125 | [email protected] "(" | ||
126 | [email protected] ")" | ||
127 | [email protected] "\n" | ||
128 | [email protected] | ||
129 | [email protected] "where" | ||
130 | [email protected] "\n " | ||
131 | [email protected] | ||
132 | [email protected] "for" | ||
133 | [email protected] | ||
134 | [email protected] "<" | ||
135 | [email protected] | ||
136 | [email protected] "\'a" | ||
137 | [email protected] ">" | ||
138 | [email protected] " " | ||
139 | [email protected] | ||
140 | [email protected] "(" | ||
141 | [email protected] | ||
142 | [email protected] "&" | ||
143 | [email protected] "\'a" | ||
144 | [email protected] " " | ||
145 | [email protected] | ||
146 | [email protected] | ||
147 | [email protected] | ||
148 | [email protected] | ||
149 | [email protected] "F" | ||
150 | [email protected] ")" | ||
151 | [email protected] ":" | ||
152 | [email protected] " " | ||
153 | [email protected] | ||
154 | [email protected] | ||
155 | [email protected] | ||
156 | [email protected] | ||
157 | [email protected] | ||
158 | [email protected] | ||
159 | [email protected] "Fn" | ||
160 | [email protected] | ||
161 | [email protected] "(" | ||
162 | [email protected] | ||
163 | [email protected] | ||
164 | [email protected] "&" | ||
165 | [email protected] "\'a" | ||
166 | [email protected] " " | ||
167 | [email protected] | ||
168 | [email protected] | ||
169 | [email protected] | ||
170 | [email protected] | ||
171 | [email protected] "str" | ||
172 | [email protected] ")" | ||
173 | [email protected] "," | ||
174 | [email protected] "\n" | ||
175 | [email protected] | ||
176 | [email protected] "{" | ||
177 | [email protected] "\n" | ||
178 | [email protected] "}" | ||
179 | [email protected] "\n" | ||
180 | [email protected] | ||
181 | [email protected] "fn" | ||
182 | [email protected] " " | ||
183 | [email protected] | ||
184 | [email protected] "for_slice" | ||
185 | [email protected] | ||
186 | [email protected] "<" | ||
187 | [email protected] | ||
188 | [email protected] | ||
189 | [email protected] "F" | ||
190 | [email protected] ">" | ||
191 | [email protected] | ||
192 | [email protected] "(" | ||
193 | [email protected] ")" | ||
194 | [email protected] "\n" | ||
195 | [email protected] | ||
196 | [email protected] "where" | ||
197 | [email protected] "\n " | ||
198 | [email protected] | ||
199 | [email protected] "for" | ||
200 | [email protected] | ||
201 | [email protected] "<" | ||
202 | [email protected] | ||
203 | [email protected] "\'a" | ||
204 | [email protected] ">" | ||
205 | [email protected] " " | ||
206 | [email protected] | ||
207 | [email protected] "[" | ||
208 | [email protected] | ||
209 | [email protected] "&" | ||
210 | [email protected] "\'a" | ||
211 | [email protected] " " | ||
212 | [email protected] | ||
213 | [email protected] | ||
214 | [email protected] | ||
215 | [email protected] | ||
216 | [email protected] "F" | ||
217 | [email protected] "]" | ||
218 | [email protected] ":" | ||
219 | [email protected] " " | ||
220 | [email protected] | ||
221 | [email protected] | ||
222 | [email protected] | ||
223 | [email protected] | ||
224 | [email protected] | ||
225 | [email protected] | ||
226 | [email protected] "Eq" | ||
227 | [email protected] "," | ||
228 | [email protected] "\n" | ||
229 | [email protected] | ||
230 | [email protected] "{" | ||
231 | [email protected] "\n" | ||
232 | [email protected] "}" | ||
233 | [email protected] "\n" | ||
234 | [email protected] | ||
235 | [email protected] "fn" | ||
236 | [email protected] " " | ||
237 | [email protected] | ||
238 | [email protected] "for_qpath" | ||
239 | [email protected] | ||
240 | [email protected] "<" | ||
241 | [email protected] | ||
242 | [email protected] | ||
243 | [email protected] "T" | ||
244 | [email protected] ">" | ||
245 | [email protected] | ||
246 | [email protected] "(" | ||
247 | [email protected] | ||
248 | [email protected] | ||
249 | [email protected] | ||
250 | [email protected] "_t" | ||
251 | [email protected] ":" | ||
252 | [email protected] " " | ||
253 | [email protected] | ||
254 | [email protected] "&" | ||
255 | [email protected] | ||
256 | [email protected] | ||
257 | [email protected] | ||
258 | [email protected] | ||
259 | [email protected] "T" | ||
260 | [email protected] ")" | ||
261 | [email protected] "\n" | ||
262 | [email protected] | ||
263 | [email protected] "where" | ||
264 | [email protected] "\n " | ||
265 | [email protected] | ||
266 | [email protected] "for" | ||
267 | [email protected] | ||
268 | [email protected] "<" | ||
269 | [email protected] | ||
270 | [email protected] "\'a" | ||
271 | [email protected] ">" | ||
272 | [email protected] " " | ||
273 | [email protected] | ||
274 | [email protected] | ||
275 | [email protected] | ||
276 | [email protected] | ||
277 | [email protected] "<" | ||
278 | [email protected] | ||
279 | [email protected] "&" | ||
280 | [email protected] "\'a" | ||
281 | [email protected] " " | ||
282 | [email protected] | ||
283 | [email protected] | ||
284 | [email protected] | ||
285 | [email protected] | ||
286 | [email protected] "T" | ||
287 | [email protected] " " | ||
288 | [email protected] "as" | ||
289 | [email protected] " " | ||
290 | [email protected] | ||
291 | [email protected] | ||
292 | [email protected] | ||
293 | [email protected] | ||
294 | [email protected] "Baz" | ||
295 | [email protected] ">" | ||
296 | [email protected] "::" | ||
297 | [email protected] | ||
298 | [email protected] | ||
299 | [email protected] "Foo" | ||
300 | [email protected] ":" | ||
301 | [email protected] " " | ||
302 | [email protected] | ||
303 | [email protected] | ||
304 | [email protected] | ||
305 | [email protected] | ||
306 | [email protected] | ||
307 | [email protected] | ||
308 | [email protected] "Iterator" | ||
309 | [email protected] "," | ||
310 | [email protected] "\n" | ||
311 | [email protected] | ||
312 | [email protected] "{" | ||
313 | [email protected] "\n" | ||
314 | [email protected] "}" | ||
315 | [email protected] "\n" | ||
316 | [email protected] | ||
317 | [email protected] "fn" | ||
318 | [email protected] " " | ||
319 | [email protected] | ||
320 | [email protected] "for_for_fn" | ||
321 | [email protected] | ||
322 | [email protected] "<" | ||
323 | [email protected] | ||
324 | [email protected] | ||
325 | [email protected] "T" | ||
326 | [email protected] ">" | ||
327 | [email protected] | ||
328 | [email protected] "(" | ||
329 | [email protected] ")" | ||
330 | [email protected] "\n" | ||
331 | [email protected] | ||
332 | [email protected] "where" | ||
333 | [email protected] "\n " | ||
334 | [email protected] | ||
335 | [email protected] "for" | ||
336 | [email protected] | ||
337 | [email protected] "<" | ||
338 | [email protected] | ||
339 | [email protected] "\'a" | ||
340 | [email protected] ">" | ||
341 | [email protected] " " | ||
342 | [email protected] | ||
343 | [email protected] "for" | ||
344 | [email protected] | ||
345 | [email protected] "<" | ||
346 | [email protected] | ||
347 | [email protected] "\'b" | ||
348 | [email protected] ">" | ||
349 | [email protected] " " | ||
350 | [email protected] | ||
351 | [email protected] "fn" | ||
352 | [email protected] | ||
353 | [email protected] "(" | ||
354 | [email protected] | ||
355 | [email protected] | ||
356 | [email protected] "&" | ||
357 | [email protected] "\'a" | ||
358 | [email protected] " " | ||
359 | [email protected] | ||
360 | [email protected] | ||
361 | [email protected] | ||
362 | [email protected] | ||
363 | [email protected] "T" | ||
364 | [email protected] "," | ||
365 | [email protected] " " | ||
366 | [email protected] | ||
367 | [email protected] | ||
368 | [email protected] "&" | ||
369 | [email protected] "\'b" | ||
370 | [email protected] " " | ||
371 | [email protected] | ||
372 | [email protected] | ||
373 | [email protected] | ||
374 | [email protected] | ||
375 | [email protected] "T" | ||
376 | [email protected] ")" | ||
377 | [email protected] ":" | ||
378 | [email protected] " " | ||
379 | [email protected] | ||
380 | [email protected] | ||
381 | [email protected] | ||
382 | [email protected] | ||
383 | [email protected] | ||
384 | [email protected] | ||
385 | [email protected] "Copy" | ||
386 | [email protected] "," | ||
387 | [email protected] "\n" | ||
388 | [email protected] | ||
389 | [email protected] "{" | ||
390 | [email protected] "\n" | ||
391 | [email protected] "}" | ||
392 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs new file mode 100644 index 000000000..9058c4619 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rs | |||
@@ -0,0 +1,30 @@ | |||
1 | fn for_trait<F>() | ||
2 | where | ||
3 | for<'a> F: Fn(&'a str), | ||
4 | { | ||
5 | } | ||
6 | fn for_ref<F>() | ||
7 | where | ||
8 | for<'a> &'a F: Debug, | ||
9 | { | ||
10 | } | ||
11 | fn for_parens<F>() | ||
12 | where | ||
13 | for<'a> (&'a F): Fn(&'a str), | ||
14 | { | ||
15 | } | ||
16 | fn for_slice<F>() | ||
17 | where | ||
18 | for<'a> [&'a F]: Eq, | ||
19 | { | ||
20 | } | ||
21 | fn for_qpath<T>(_t: &T) | ||
22 | where | ||
23 | for<'a> <&'a T as Baz>::Foo: Iterator, | ||
24 | { | ||
25 | } | ||
26 | fn for_for_fn<T>() | ||
27 | where | ||
28 | for<'a> for<'b> fn(&'a T, &'b T): Copy, | ||
29 | { | ||
30 | } | ||
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 65b487db3..458089e53 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -10,7 +10,7 @@ doctest = false | |||
10 | 10 | ||
11 | [[bin]] | 11 | [[bin]] |
12 | name = "rust-analyzer" | 12 | name = "rust-analyzer" |
13 | path = "./src/bin/main.rs" | 13 | path = "src/bin/main.rs" |
14 | 14 | ||
15 | [dependencies] | 15 | [dependencies] |
16 | anyhow = "1.0.26" | 16 | anyhow = "1.0.26" |
@@ -32,7 +32,7 @@ threadpool = "1.7.1" | |||
32 | 32 | ||
33 | stdx = { path = "../stdx" } | 33 | stdx = { path = "../stdx" } |
34 | 34 | ||
35 | lsp-server = "0.3.1" | 35 | lsp-server = "0.3.2" |
36 | ra_flycheck = { path = "../ra_flycheck" } | 36 | ra_flycheck = { path = "../ra_flycheck" } |
37 | ra_ide = { path = "../ra_ide" } | 37 | ra_ide = { path = "../ra_ide" } |
38 | ra_prof = { path = "../ra_prof" } | 38 | ra_prof = { path = "../ra_prof" } |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index e82fd57de..8d071ab1c 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -4,9 +4,14 @@ | |||
4 | mod args; | 4 | mod args; |
5 | 5 | ||
6 | use lsp_server::Connection; | 6 | use lsp_server::Connection; |
7 | use rust_analyzer::{cli, config::Config, from_json, Result}; | 7 | use rust_analyzer::{ |
8 | cli, | ||
9 | config::{Config, LinkedProject}, | ||
10 | from_json, Result, | ||
11 | }; | ||
8 | 12 | ||
9 | use crate::args::HelpPrinted; | 13 | use crate::args::HelpPrinted; |
14 | use ra_project_model::ProjectManifest; | ||
10 | 15 | ||
11 | fn main() -> Result<()> { | 16 | fn main() -> Result<()> { |
12 | setup_logging()?; | 17 | setup_logging()?; |
@@ -97,17 +102,6 @@ fn run_server() -> Result<()> { | |||
97 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); | 102 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); |
98 | } | 103 | } |
99 | 104 | ||
100 | let cwd = std::env::current_dir()?; | ||
101 | let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); | ||
102 | |||
103 | let workspace_roots = initialize_params | ||
104 | .workspace_folders | ||
105 | .map(|workspaces| { | ||
106 | workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::<Vec<_>>() | ||
107 | }) | ||
108 | .filter(|workspaces| !workspaces.is_empty()) | ||
109 | .unwrap_or_else(|| vec![root]); | ||
110 | |||
111 | let config = { | 105 | let config = { |
112 | let mut config = Config::default(); | 106 | let mut config = Config::default(); |
113 | if let Some(value) = &initialize_params.initialization_options { | 107 | if let Some(value) = &initialize_params.initialization_options { |
@@ -115,10 +109,31 @@ fn run_server() -> Result<()> { | |||
115 | } | 109 | } |
116 | config.update_caps(&initialize_params.capabilities); | 110 | config.update_caps(&initialize_params.capabilities); |
117 | 111 | ||
112 | if config.linked_projects.is_empty() { | ||
113 | let cwd = std::env::current_dir()?; | ||
114 | let root = | ||
115 | initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); | ||
116 | let workspace_roots = initialize_params | ||
117 | .workspace_folders | ||
118 | .map(|workspaces| { | ||
119 | workspaces | ||
120 | .into_iter() | ||
121 | .filter_map(|it| it.uri.to_file_path().ok()) | ||
122 | .collect::<Vec<_>>() | ||
123 | }) | ||
124 | .filter(|workspaces| !workspaces.is_empty()) | ||
125 | .unwrap_or_else(|| vec![root]); | ||
126 | |||
127 | config.linked_projects = ProjectManifest::discover_all(&workspace_roots) | ||
128 | .into_iter() | ||
129 | .map(LinkedProject::from) | ||
130 | .collect(); | ||
131 | } | ||
132 | |||
118 | config | 133 | config |
119 | }; | 134 | }; |
120 | 135 | ||
121 | rust_analyzer::main_loop(workspace_roots, config, connection)?; | 136 | rust_analyzer::main_loop(config, connection)?; |
122 | 137 | ||
123 | log::info!("shutting down IO..."); | 138 | log::info!("shutting down IO..."); |
124 | io_threads.join()?; | 139 | io_threads.join()?; |
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 345693524..673795e78 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -87,6 +87,9 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti | |||
87 | "ssr": true, | 87 | "ssr": true, |
88 | "onEnter": true, | 88 | "onEnter": true, |
89 | "parentModule": true, | 89 | "parentModule": true, |
90 | "runnables": { | ||
91 | "kinds": [ "cargo" ], | ||
92 | }, | ||
90 | })), | 93 | })), |
91 | } | 94 | } |
92 | } | 95 | } |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 441fb61df..44f856f6b 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! See `CargoTargetSpec` | 1 | //! See `CargoTargetSpec` |
2 | 2 | ||
3 | use ra_cfg::CfgExpr; | ||
3 | use ra_ide::{FileId, RunnableKind, TestId}; | 4 | use ra_ide::{FileId, RunnableKind, TestId}; |
4 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; | 5 | use ra_project_model::{self, ProjectWorkspace, TargetKind}; |
5 | 6 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 7 | use crate::{global_state::GlobalStateSnapshot, Result}; |
7 | use ra_syntax::SmolStr; | ||
8 | 8 | ||
9 | /// Abstract representation of Cargo target. | 9 | /// Abstract representation of Cargo target. |
10 | /// | 10 | /// |
@@ -21,7 +21,7 @@ impl CargoTargetSpec { | |||
21 | pub(crate) fn runnable_args( | 21 | pub(crate) fn runnable_args( |
22 | spec: Option<CargoTargetSpec>, | 22 | spec: Option<CargoTargetSpec>, |
23 | kind: &RunnableKind, | 23 | kind: &RunnableKind, |
24 | features_needed: &Vec<SmolStr>, | 24 | cfgs: &[CfgExpr], |
25 | ) -> Result<(Vec<String>, Vec<String>)> { | 25 | ) -> Result<(Vec<String>, Vec<String>)> { |
26 | let mut args = Vec::new(); | 26 | let mut args = Vec::new(); |
27 | let mut extra_args = Vec::new(); | 27 | let mut extra_args = Vec::new(); |
@@ -76,16 +76,20 @@ impl CargoTargetSpec { | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | features_needed.iter().for_each(|feature| { | 79 | let mut features = Vec::new(); |
80 | for cfg in cfgs { | ||
81 | required_features(cfg, &mut features); | ||
82 | } | ||
83 | for feature in features { | ||
80 | args.push("--features".to_string()); | 84 | args.push("--features".to_string()); |
81 | args.push(feature.to_string()); | 85 | args.push(feature); |
82 | }); | 86 | } |
83 | 87 | ||
84 | Ok((args, extra_args)) | 88 | Ok((args, extra_args)) |
85 | } | 89 | } |
86 | 90 | ||
87 | pub(crate) fn for_file( | 91 | pub(crate) fn for_file( |
88 | world: &WorldSnapshot, | 92 | world: &GlobalStateSnapshot, |
89 | file_id: FileId, | 93 | file_id: FileId, |
90 | ) -> Result<Option<CargoTargetSpec>> { | 94 | ) -> Result<Option<CargoTargetSpec>> { |
91 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { | 95 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { |
@@ -140,3 +144,74 @@ impl CargoTargetSpec { | |||
140 | } | 144 | } |
141 | } | 145 | } |
142 | } | 146 | } |
147 | |||
148 | /// Fill minimal features needed | ||
149 | fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) { | ||
150 | match cfg_expr { | ||
151 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.to_string()), | ||
152 | CfgExpr::All(preds) => { | ||
153 | preds.iter().for_each(|cfg| required_features(cfg, features)); | ||
154 | } | ||
155 | CfgExpr::Any(preds) => { | ||
156 | for cfg in preds { | ||
157 | let len_features = features.len(); | ||
158 | required_features(cfg, features); | ||
159 | if len_features != features.len() { | ||
160 | break; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | _ => {} | ||
165 | } | ||
166 | } | ||
167 | |||
168 | #[cfg(test)] | ||
169 | mod tests { | ||
170 | use super::*; | ||
171 | |||
172 | use mbe::{ast_to_token_tree, TokenMap}; | ||
173 | use ra_cfg::parse_cfg; | ||
174 | use ra_syntax::{ | ||
175 | ast::{self, AstNode}, | ||
176 | SmolStr, | ||
177 | }; | ||
178 | |||
179 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | ||
180 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
181 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
182 | ast_to_token_tree(&tt).unwrap() | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn test_cfg_expr_minimal_features_needed() { | ||
187 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | ||
188 | let cfg_expr = parse_cfg(&subtree); | ||
189 | let mut min_features = vec![]; | ||
190 | required_features(&cfg_expr, &mut min_features); | ||
191 | |||
192 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
193 | |||
194 | let (subtree, _) = | ||
195 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | ||
196 | let cfg_expr = parse_cfg(&subtree); | ||
197 | |||
198 | let mut min_features = vec![]; | ||
199 | required_features(&cfg_expr, &mut min_features); | ||
200 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | ||
201 | |||
202 | let (subtree, _) = | ||
203 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | ||
204 | let cfg_expr = parse_cfg(&subtree); | ||
205 | |||
206 | let mut min_features = vec![]; | ||
207 | required_features(&cfg_expr, &mut min_features); | ||
208 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | ||
209 | |||
210 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | ||
211 | let cfg_expr = parse_cfg(&subtree); | ||
212 | |||
213 | let mut min_features = vec![]; | ||
214 | required_features(&cfg_expr, &mut min_features); | ||
215 | assert!(min_features.is_empty()); | ||
216 | } | ||
217 | } | ||
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 8eaf75ff6..97367d7c6 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -8,7 +8,7 @@ use crossbeam_channel::{unbounded, Receiver}; | |||
8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; | 8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; |
9 | use ra_ide::{AnalysisChange, AnalysisHost}; | 9 | use ra_ide::{AnalysisChange, AnalysisHost}; |
10 | use ra_project_model::{ | 10 | use ra_project_model::{ |
11 | get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectRoot, ProjectWorkspace, | 11 | CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, |
12 | }; | 12 | }; |
13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 14 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -28,7 +28,7 @@ pub fn load_cargo( | |||
28 | with_proc_macro: bool, | 28 | with_proc_macro: bool, |
29 | ) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { | 29 | ) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { |
30 | let root = std::env::current_dir()?.join(root); | 30 | let root = std::env::current_dir()?.join(root); |
31 | let root = ProjectRoot::discover_single(&root)?; | 31 | let root = ProjectManifest::discover_single(&root)?; |
32 | let ws = ProjectWorkspace::load( | 32 | let ws = ProjectWorkspace::load( |
33 | root, | 33 | root, |
34 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, | 34 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, |
@@ -36,28 +36,28 @@ pub fn load_cargo( | |||
36 | )?; | 36 | )?; |
37 | 37 | ||
38 | let mut extern_dirs = FxHashSet::default(); | 38 | let mut extern_dirs = FxHashSet::default(); |
39 | extern_dirs.extend(ws.out_dirs()); | ||
40 | |||
41 | let mut project_roots = ws.to_roots(); | ||
42 | project_roots.extend(extern_dirs.iter().cloned().map(PackageRoot::new_non_member)); | ||
43 | 39 | ||
44 | let (sender, receiver) = unbounded(); | 40 | let (sender, receiver) = unbounded(); |
45 | let sender = Box::new(move |t| sender.send(t).unwrap()); | 41 | let sender = Box::new(move |t| sender.send(t).unwrap()); |
46 | let (mut vfs, roots) = Vfs::new( | 42 | |
47 | project_roots | 43 | let mut roots = Vec::new(); |
48 | .iter() | 44 | let project_roots = ws.to_roots(); |
49 | .map(|pkg_root| { | 45 | for root in &project_roots { |
50 | RootEntry::new( | 46 | roots.push(RootEntry::new( |
51 | pkg_root.path().to_owned(), | 47 | root.path().to_owned(), |
52 | RustPackageFilterBuilder::default() | 48 | RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), |
53 | .set_member(pkg_root.is_member()) | 49 | )); |
54 | .into_vfs_filter(), | 50 | |
55 | ) | 51 | if let Some(out_dir) = root.out_dir() { |
56 | }) | 52 | extern_dirs.insert(out_dir.to_path_buf()); |
57 | .collect(), | 53 | roots.push(RootEntry::new( |
58 | sender, | 54 | out_dir.to_owned(), |
59 | Watch(false), | 55 | RustPackageFilterBuilder::default().set_member(root.is_member()).into_vfs_filter(), |
60 | ); | 56 | )) |
57 | } | ||
58 | } | ||
59 | |||
60 | let (mut vfs, roots) = Vfs::new(roots, sender, Watch(false)); | ||
61 | 61 | ||
62 | let source_roots = roots | 62 | let source_roots = roots |
63 | .into_iter() | 63 | .into_iter() |
@@ -111,10 +111,6 @@ pub(crate) fn load( | |||
111 | vfs.root2path(root) | 111 | vfs.root2path(root) |
112 | ); | 112 | ); |
113 | analysis_change.add_root(source_root_id, is_local); | 113 | analysis_change.add_root(source_root_id, is_local); |
114 | analysis_change.set_debug_root_path( | ||
115 | source_root_id, | ||
116 | source_roots[&source_root_id].path().display().to_string(), | ||
117 | ); | ||
118 | 114 | ||
119 | let vfs_root_path = vfs.root2path(root); | 115 | let vfs_root_path = vfs.root2path(root); |
120 | if extern_dirs.contains(&vfs_root_path) { | 116 | if extern_dirs.contains(&vfs_root_path) { |
@@ -147,26 +143,14 @@ pub(crate) fn load( | |||
147 | } | 143 | } |
148 | } | 144 | } |
149 | 145 | ||
150 | // FIXME: cfg options? | 146 | let crate_graph = |
151 | let default_cfg_options = { | 147 | ws.to_crate_graph(None, &extern_source_roots, proc_macro_client, &mut |path: &Path| { |
152 | let mut opts = get_rustc_cfg_options(None); | ||
153 | opts.insert_atom("test".into()); | ||
154 | opts.insert_atom("debug_assertion".into()); | ||
155 | opts | ||
156 | }; | ||
157 | |||
158 | let crate_graph = ws.to_crate_graph( | ||
159 | &default_cfg_options, | ||
160 | &extern_source_roots, | ||
161 | proc_macro_client, | ||
162 | &mut |path: &Path| { | ||
163 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs | 148 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs |
164 | let path = path.canonicalize().ok()?; | 149 | let path = path.canonicalize().ok()?; |
165 | let vfs_file = vfs.load(&path); | 150 | let vfs_file = vfs.load(&path); |
166 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 151 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); |
167 | vfs_file.map(vfs_file_to_id) | 152 | vfs_file.map(vfs_file_to_id) |
168 | }, | 153 | }); |
169 | ); | ||
170 | log::debug!("crate graph: {:?}", crate_graph); | 154 | log::debug!("crate graph: {:?}", crate_graph); |
171 | analysis_change.set_crate_graph(crate_graph); | 155 | analysis_change.set_crate_graph(crate_graph); |
172 | 156 | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c0f7c2c0c..1253db836 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -11,15 +11,14 @@ use std::{ffi::OsString, path::PathBuf}; | |||
11 | 11 | ||
12 | use lsp_types::ClientCapabilities; | 12 | use lsp_types::ClientCapabilities; |
13 | use ra_flycheck::FlycheckConfig; | 13 | use ra_flycheck::FlycheckConfig; |
14 | use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; | 14 | use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; |
15 | use ra_project_model::CargoConfig; | 15 | use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; |
16 | use serde::Deserialize; | 16 | use serde::Deserialize; |
17 | 17 | ||
18 | #[derive(Debug, Clone)] | 18 | #[derive(Debug, Clone)] |
19 | pub struct Config { | 19 | pub struct Config { |
20 | pub client_caps: ClientCapsConfig, | 20 | pub client_caps: ClientCapsConfig, |
21 | 21 | ||
22 | pub with_sysroot: bool, | ||
23 | pub publish_diagnostics: bool, | 22 | pub publish_diagnostics: bool, |
24 | pub lru_capacity: Option<usize>, | 23 | pub lru_capacity: Option<usize>, |
25 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, | 24 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, |
@@ -35,6 +34,28 @@ pub struct Config { | |||
35 | pub assist: AssistConfig, | 34 | pub assist: AssistConfig, |
36 | pub call_info_full: bool, | 35 | pub call_info_full: bool, |
37 | pub lens: LensConfig, | 36 | pub lens: LensConfig, |
37 | pub hover: HoverConfig, | ||
38 | |||
39 | pub with_sysroot: bool, | ||
40 | pub linked_projects: Vec<LinkedProject>, | ||
41 | } | ||
42 | |||
43 | #[derive(Debug, Clone)] | ||
44 | pub enum LinkedProject { | ||
45 | ProjectManifest(ProjectManifest), | ||
46 | JsonProject(JsonProject), | ||
47 | } | ||
48 | |||
49 | impl From<ProjectManifest> for LinkedProject { | ||
50 | fn from(v: ProjectManifest) -> Self { | ||
51 | LinkedProject::ProjectManifest(v) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl From<JsonProject> for LinkedProject { | ||
56 | fn from(v: JsonProject) -> Self { | ||
57 | LinkedProject::JsonProject(v) | ||
58 | } | ||
38 | } | 59 | } |
39 | 60 | ||
40 | #[derive(Clone, Debug, PartialEq, Eq)] | 61 | #[derive(Clone, Debug, PartialEq, Eq)] |
@@ -103,6 +124,8 @@ pub struct ClientCapsConfig { | |||
103 | pub code_action_literals: bool, | 124 | pub code_action_literals: bool, |
104 | pub work_done_progress: bool, | 125 | pub work_done_progress: bool, |
105 | pub code_action_group: bool, | 126 | pub code_action_group: bool, |
127 | pub resolve_code_action: bool, | ||
128 | pub hover_actions: bool, | ||
106 | } | 129 | } |
107 | 130 | ||
108 | impl Default for Config { | 131 | impl Default for Config { |
@@ -122,8 +145,9 @@ impl Default for Config { | |||
122 | check: Some(FlycheckConfig::CargoCommand { | 145 | check: Some(FlycheckConfig::CargoCommand { |
123 | command: "check".to_string(), | 146 | command: "check".to_string(), |
124 | all_targets: true, | 147 | all_targets: true, |
125 | all_features: true, | 148 | all_features: false, |
126 | extra_args: Vec::new(), | 149 | extra_args: Vec::new(), |
150 | features: Vec::new(), | ||
127 | }), | 151 | }), |
128 | 152 | ||
129 | inlay_hints: InlayHintsConfig { | 153 | inlay_hints: InlayHintsConfig { |
@@ -141,6 +165,8 @@ impl Default for Config { | |||
141 | assist: AssistConfig::default(), | 165 | assist: AssistConfig::default(), |
142 | call_info_full: true, | 166 | call_info_full: true, |
143 | lens: LensConfig::default(), | 167 | lens: LensConfig::default(), |
168 | hover: HoverConfig::default(), | ||
169 | linked_projects: Vec::new(), | ||
144 | } | 170 | } |
145 | } | 171 | } |
146 | } | 172 | } |
@@ -209,13 +235,14 @@ impl Config { | |||
209 | } | 235 | } |
210 | // otherwise configure command customizations | 236 | // otherwise configure command customizations |
211 | _ => { | 237 | _ => { |
212 | if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features }) | 238 | if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features, features }) |
213 | = &mut self.check | 239 | = &mut self.check |
214 | { | 240 | { |
215 | set(value, "/checkOnSave/extraArgs", extra_args); | 241 | set(value, "/checkOnSave/extraArgs", extra_args); |
216 | set(value, "/checkOnSave/command", command); | 242 | set(value, "/checkOnSave/command", command); |
217 | set(value, "/checkOnSave/allTargets", all_targets); | 243 | set(value, "/checkOnSave/allTargets", all_targets); |
218 | set(value, "/checkOnSave/allFeatures", all_features); | 244 | *all_features = get(value, "/checkOnSave/allFeatures").unwrap_or(self.cargo.all_features); |
245 | *features = get(value, "/checkOnSave/features").unwrap_or(self.cargo.features.clone()); | ||
219 | } | 246 | } |
220 | } | 247 | } |
221 | }; | 248 | }; |
@@ -240,6 +267,32 @@ impl Config { | |||
240 | self.lens = LensConfig::NO_LENS; | 267 | self.lens = LensConfig::NO_LENS; |
241 | } | 268 | } |
242 | 269 | ||
270 | if let Some(linked_projects) = get::<Vec<ManifestOrJsonProject>>(value, "/linkedProjects") { | ||
271 | if !linked_projects.is_empty() { | ||
272 | self.linked_projects.clear(); | ||
273 | for linked_project in linked_projects { | ||
274 | let linked_project = match linked_project { | ||
275 | ManifestOrJsonProject::Manifest(it) => match ProjectManifest::from_manifest_file(it) { | ||
276 | Ok(it) => it.into(), | ||
277 | Err(_) => continue, | ||
278 | } | ||
279 | ManifestOrJsonProject::JsonProject(it) => it.into(), | ||
280 | }; | ||
281 | self.linked_projects.push(linked_project); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | let mut use_hover_actions = false; | ||
287 | set(value, "/hoverActions/enable", &mut use_hover_actions); | ||
288 | if use_hover_actions { | ||
289 | set(value, "/hoverActions/implementations", &mut self.hover.implementations); | ||
290 | set(value, "/hoverActions/run", &mut self.hover.run); | ||
291 | set(value, "/hoverActions/debug", &mut self.hover.debug); | ||
292 | } else { | ||
293 | self.hover = HoverConfig::NO_ACTIONS; | ||
294 | } | ||
295 | |||
243 | log::info!("Config::update() = {:#?}", self); | 296 | log::info!("Config::update() = {:#?}", self); |
244 | 297 | ||
245 | fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { | 298 | fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { |
@@ -293,13 +346,22 @@ impl Config { | |||
293 | 346 | ||
294 | self.assist.allow_snippets(false); | 347 | self.assist.allow_snippets(false); |
295 | if let Some(experimental) = &caps.experimental { | 348 | if let Some(experimental) = &caps.experimental { |
296 | let snippet_text_edit = | 349 | let get_bool = |
297 | experimental.get("snippetTextEdit").and_then(|it| it.as_bool()) == Some(true); | 350 | |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); |
351 | |||
352 | let snippet_text_edit = get_bool("snippetTextEdit"); | ||
298 | self.assist.allow_snippets(snippet_text_edit); | 353 | self.assist.allow_snippets(snippet_text_edit); |
299 | 354 | ||
300 | let code_action_group = | 355 | self.client_caps.code_action_group = get_bool("codeActionGroup"); |
301 | experimental.get("codeActionGroup").and_then(|it| it.as_bool()) == Some(true); | 356 | self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); |
302 | self.client_caps.code_action_group = code_action_group | 357 | self.client_caps.hover_actions = get_bool("hoverActions"); |
303 | } | 358 | } |
304 | } | 359 | } |
305 | } | 360 | } |
361 | |||
362 | #[derive(Deserialize)] | ||
363 | #[serde(untagged)] | ||
364 | enum ManifestOrJsonProject { | ||
365 | Manifest(PathBuf), | ||
366 | JsonProject(JsonProject), | ||
367 | } | ||
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap index c40cfdcdc..272057b47 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap | |||
@@ -65,6 +65,7 @@ expression: diag | |||
65 | fixes: [ | 65 | fixes: [ |
66 | CodeAction { | 66 | CodeAction { |
67 | title: "return the expression directly", | 67 | title: "return the expression directly", |
68 | id: None, | ||
68 | group: None, | 69 | group: None, |
69 | kind: Some( | 70 | kind: Some( |
70 | "quickfix", | 71 | "quickfix", |
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap index 6dd3fcb2e..f0273315e 100644 --- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap +++ b/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap | |||
@@ -29,7 +29,7 @@ expression: diag | |||
29 | }, | 29 | }, |
30 | }, | 30 | }, |
31 | severity: Some( | 31 | severity: Some( |
32 | Warning, | 32 | Hint, |
33 | ), | 33 | ), |
34 | code: Some( | 34 | code: Some( |
35 | String( | 35 | String( |
@@ -50,6 +50,7 @@ expression: diag | |||
50 | fixes: [ | 50 | fixes: [ |
51 | CodeAction { | 51 | CodeAction { |
52 | title: "consider prefixing with an underscore", | 52 | title: "consider prefixing with an underscore", |
53 | id: None, | ||
53 | group: None, | 54 | group: None, |
54 | kind: Some( | 55 | kind: Some( |
55 | "quickfix", | 56 | "quickfix", |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index a500d670a..04e286780 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -145,6 +145,7 @@ fn map_rust_child_diagnostic( | |||
145 | } else { | 145 | } else { |
146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { | 146 | MappedRustChildDiagnostic::SuggestedFix(lsp_ext::CodeAction { |
147 | title: rd.message.clone(), | 147 | title: rd.message.clone(), |
148 | id: None, | ||
148 | group: None, | 149 | group: None, |
149 | kind: Some("quickfix".to_string()), | 150 | kind: Some("quickfix".to_string()), |
150 | edit: Some(lsp_ext::SnippetWorkspaceEdit { | 151 | edit: Some(lsp_ext::SnippetWorkspaceEdit { |
@@ -183,7 +184,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
183 | return Vec::new(); | 184 | return Vec::new(); |
184 | } | 185 | } |
185 | 186 | ||
186 | let severity = map_level_to_severity(rd.level); | 187 | let mut severity = map_level_to_severity(rd.level); |
187 | 188 | ||
188 | let mut source = String::from("rustc"); | 189 | let mut source = String::from("rustc"); |
189 | let mut code = rd.code.as_ref().map(|c| c.code.clone()); | 190 | let mut code = rd.code.as_ref().map(|c| c.code.clone()); |
@@ -225,6 +226,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
225 | } | 226 | } |
226 | 227 | ||
227 | if is_unused_or_unnecessary(rd) { | 228 | if is_unused_or_unnecessary(rd) { |
229 | severity = Some(DiagnosticSeverity::Hint); | ||
228 | tags.push(DiagnosticTag::Unnecessary); | 230 | tags.push(DiagnosticTag::Unnecessary); |
229 | } | 231 | } |
230 | 232 | ||
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 4bb16a496..206673829 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs | |||
@@ -3,7 +3,7 @@ use ra_db::{FileId, FilePosition, FileRange}; | |||
3 | use ra_ide::{LineCol, LineIndex}; | 3 | use ra_ide::{LineCol, LineIndex}; |
4 | use ra_syntax::{TextRange, TextSize}; | 4 | use ra_syntax::{TextRange, TextSize}; |
5 | 5 | ||
6 | use crate::{world::WorldSnapshot, Result}; | 6 | use crate::{global_state::GlobalStateSnapshot, Result}; |
7 | 7 | ||
8 | pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { | 8 | pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { |
9 | let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 }; | 9 | let line_col = LineCol { line: position.line as u32, col_utf16: position.character as u32 }; |
@@ -16,12 +16,12 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Tex | |||
16 | TextRange::new(start, end) | 16 | TextRange::new(start, end) |
17 | } | 17 | } |
18 | 18 | ||
19 | pub(crate) fn file_id(world: &WorldSnapshot, url: &lsp_types::Url) -> Result<FileId> { | 19 | pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> { |
20 | world.uri_to_file_id(url) | 20 | world.uri_to_file_id(url) |
21 | } | 21 | } |
22 | 22 | ||
23 | pub(crate) fn file_position( | 23 | pub(crate) fn file_position( |
24 | world: &WorldSnapshot, | 24 | world: &GlobalStateSnapshot, |
25 | tdpp: lsp_types::TextDocumentPositionParams, | 25 | tdpp: lsp_types::TextDocumentPositionParams, |
26 | ) -> Result<FilePosition> { | 26 | ) -> Result<FilePosition> { |
27 | let file_id = file_id(world, &tdpp.text_document.uri)?; | 27 | let file_id = file_id(world, &tdpp.text_document.uri)?; |
@@ -31,7 +31,7 @@ pub(crate) fn file_position( | |||
31 | } | 31 | } |
32 | 32 | ||
33 | pub(crate) fn file_range( | 33 | pub(crate) fn file_range( |
34 | world: &WorldSnapshot, | 34 | world: &GlobalStateSnapshot, |
35 | text_document_identifier: lsp_types::TextDocumentIdentifier, | 35 | text_document_identifier: lsp_types::TextDocumentIdentifier, |
36 | range: lsp_types::Range, | 36 | range: lsp_types::Range, |
37 | ) -> Result<FileRange> { | 37 | ) -> Result<FileRange> { |
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/global_state.rs index 367272925..21116e165 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -15,7 +15,7 @@ use ra_flycheck::{Flycheck, FlycheckConfig}; | |||
15 | use ra_ide::{ | 15 | use ra_ide::{ |
16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, | 16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, |
17 | }; | 17 | }; |
18 | use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace}; | 18 | use ra_project_model::{ProcMacroClient, ProjectWorkspace}; |
19 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; | 19 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; |
20 | use relative_path::RelativePathBuf; | 20 | use relative_path::RelativePathBuf; |
21 | use stdx::format_to; | 21 | use stdx::format_to; |
@@ -50,15 +50,15 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> | |||
50 | }) | 50 | }) |
51 | } | 51 | } |
52 | 52 | ||
53 | /// `WorldState` is the primary mutable state of the language server | 53 | /// `GlobalState` is the primary mutable state of the language server |
54 | /// | 54 | /// |
55 | /// The most interesting components are `vfs`, which stores a consistent | 55 | /// The most interesting components are `vfs`, which stores a consistent |
56 | /// snapshot of the file systems, and `analysis_host`, which stores our | 56 | /// snapshot of the file systems, and `analysis_host`, which stores our |
57 | /// incremental salsa database. | 57 | /// incremental salsa database. |
58 | #[derive(Debug)] | 58 | #[derive(Debug)] |
59 | pub struct WorldState { | 59 | pub struct GlobalState { |
60 | pub config: Config, | 60 | pub config: Config, |
61 | pub roots: Vec<PathBuf>, | 61 | pub local_roots: Vec<PathBuf>, |
62 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 62 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
63 | pub analysis_host: AnalysisHost, | 63 | pub analysis_host: AnalysisHost, |
64 | pub vfs: Arc<RwLock<Vfs>>, | 64 | pub vfs: Arc<RwLock<Vfs>>, |
@@ -70,7 +70,7 @@ pub struct WorldState { | |||
70 | } | 70 | } |
71 | 71 | ||
72 | /// An immutable snapshot of the world's state at a point in time. | 72 | /// An immutable snapshot of the world's state at a point in time. |
73 | pub struct WorldSnapshot { | 73 | pub struct GlobalStateSnapshot { |
74 | pub config: Config, | 74 | pub config: Config, |
75 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 75 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
76 | pub analysis: Analysis, | 76 | pub analysis: Analysis, |
@@ -79,20 +79,19 @@ pub struct WorldSnapshot { | |||
79 | vfs: Arc<RwLock<Vfs>>, | 79 | vfs: Arc<RwLock<Vfs>>, |
80 | } | 80 | } |
81 | 81 | ||
82 | impl WorldState { | 82 | impl GlobalState { |
83 | pub fn new( | 83 | pub fn new( |
84 | folder_roots: Vec<PathBuf>, | ||
85 | workspaces: Vec<ProjectWorkspace>, | 84 | workspaces: Vec<ProjectWorkspace>, |
86 | lru_capacity: Option<usize>, | 85 | lru_capacity: Option<usize>, |
87 | exclude_globs: &[Glob], | 86 | exclude_globs: &[Glob], |
88 | watch: Watch, | 87 | watch: Watch, |
89 | config: Config, | 88 | config: Config, |
90 | ) -> WorldState { | 89 | ) -> GlobalState { |
91 | let mut change = AnalysisChange::new(); | 90 | let mut change = AnalysisChange::new(); |
92 | 91 | ||
93 | let extern_dirs: FxHashSet<_> = | 92 | let mut extern_dirs: FxHashSet<PathBuf> = FxHashSet::default(); |
94 | workspaces.iter().flat_map(ProjectWorkspace::out_dirs).collect(); | ||
95 | 93 | ||
94 | let mut local_roots = Vec::new(); | ||
96 | let roots: Vec<_> = { | 95 | let roots: Vec<_> = { |
97 | let create_filter = |is_member| { | 96 | let create_filter = |is_member| { |
98 | RustPackageFilterBuilder::default() | 97 | RustPackageFilterBuilder::default() |
@@ -100,18 +99,22 @@ impl WorldState { | |||
100 | .exclude(exclude_globs.iter().cloned()) | 99 | .exclude(exclude_globs.iter().cloned()) |
101 | .into_vfs_filter() | 100 | .into_vfs_filter() |
102 | }; | 101 | }; |
103 | folder_roots | 102 | let mut roots = Vec::new(); |
104 | .iter() | 103 | for root in workspaces.iter().flat_map(ProjectWorkspace::to_roots) { |
105 | .map(|path| RootEntry::new(path.clone(), create_filter(true))) | 104 | let path = root.path().to_owned(); |
106 | .chain(workspaces.iter().flat_map(ProjectWorkspace::to_roots).map(|pkg_root| { | 105 | if root.is_member() { |
107 | RootEntry::new(pkg_root.path().to_owned(), create_filter(pkg_root.is_member())) | 106 | local_roots.push(path.clone()); |
108 | })) | 107 | } |
109 | .chain( | 108 | roots.push(RootEntry::new(path, create_filter(root.is_member()))); |
110 | extern_dirs | 109 | if let Some(out_dir) = root.out_dir() { |
111 | .iter() | 110 | extern_dirs.insert(out_dir.to_path_buf()); |
112 | .map(|path| RootEntry::new(path.to_owned(), create_filter(false))), | 111 | roots.push(RootEntry::new( |
113 | ) | 112 | out_dir.to_path_buf(), |
114 | .collect() | 113 | create_filter(root.is_member()), |
114 | )) | ||
115 | } | ||
116 | } | ||
117 | roots | ||
115 | }; | 118 | }; |
116 | 119 | ||
117 | let (task_sender, task_receiver) = unbounded(); | 120 | let (task_sender, task_receiver) = unbounded(); |
@@ -121,9 +124,8 @@ impl WorldState { | |||
121 | let mut extern_source_roots = FxHashMap::default(); | 124 | let mut extern_source_roots = FxHashMap::default(); |
122 | for r in vfs_roots { | 125 | for r in vfs_roots { |
123 | let vfs_root_path = vfs.root2path(r); | 126 | let vfs_root_path = vfs.root2path(r); |
124 | let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it)); | 127 | let is_local = local_roots.iter().any(|it| vfs_root_path.starts_with(it)); |
125 | change.add_root(SourceRootId(r.0), is_local); | 128 | change.add_root(SourceRootId(r.0), is_local); |
126 | change.set_debug_root_path(SourceRootId(r.0), vfs_root_path.display().to_string()); | ||
127 | 129 | ||
128 | // FIXME: add path2root in vfs to simpily this logic | 130 | // FIXME: add path2root in vfs to simpily this logic |
129 | if extern_dirs.contains(&vfs_root_path) { | 131 | if extern_dirs.contains(&vfs_root_path) { |
@@ -131,14 +133,6 @@ impl WorldState { | |||
131 | } | 133 | } |
132 | } | 134 | } |
133 | 135 | ||
134 | // FIXME: Read default cfgs from config | ||
135 | let default_cfg_options = { | ||
136 | let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); | ||
137 | opts.insert_atom("test".into()); | ||
138 | opts.insert_atom("debug_assertion".into()); | ||
139 | opts | ||
140 | }; | ||
141 | |||
142 | let proc_macro_client = match &config.proc_macro_srv { | 136 | let proc_macro_client = match &config.proc_macro_srv { |
143 | None => ProcMacroClient::dummy(), | 137 | None => ProcMacroClient::dummy(), |
144 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { | 138 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { |
@@ -164,7 +158,7 @@ impl WorldState { | |||
164 | }; | 158 | }; |
165 | for ws in workspaces.iter() { | 159 | for ws in workspaces.iter() { |
166 | crate_graph.extend(ws.to_crate_graph( | 160 | crate_graph.extend(ws.to_crate_graph( |
167 | &default_cfg_options, | 161 | config.cargo.target.as_deref(), |
168 | &extern_source_roots, | 162 | &extern_source_roots, |
169 | &proc_macro_client, | 163 | &proc_macro_client, |
170 | &mut load, | 164 | &mut load, |
@@ -176,9 +170,9 @@ impl WorldState { | |||
176 | 170 | ||
177 | let mut analysis_host = AnalysisHost::new(lru_capacity); | 171 | let mut analysis_host = AnalysisHost::new(lru_capacity); |
178 | analysis_host.apply_change(change); | 172 | analysis_host.apply_change(change); |
179 | WorldState { | 173 | GlobalState { |
180 | config, | 174 | config, |
181 | roots: folder_roots, | 175 | local_roots, |
182 | workspaces: Arc::new(workspaces), | 176 | workspaces: Arc::new(workspaces), |
183 | analysis_host, | 177 | analysis_host, |
184 | vfs: Arc::new(RwLock::new(vfs)), | 178 | vfs: Arc::new(RwLock::new(vfs)), |
@@ -216,7 +210,7 @@ impl WorldState { | |||
216 | match c { | 210 | match c { |
217 | VfsChange::AddRoot { root, files } => { | 211 | VfsChange::AddRoot { root, files } => { |
218 | let root_path = self.vfs.read().root2path(root); | 212 | let root_path = self.vfs.read().root2path(root); |
219 | let is_local = self.roots.iter().any(|r| root_path.starts_with(r)); | 213 | let is_local = self.local_roots.iter().any(|r| root_path.starts_with(r)); |
220 | if is_local { | 214 | if is_local { |
221 | *roots_scanned += 1; | 215 | *roots_scanned += 1; |
222 | for (file, path, text) in files { | 216 | for (file, path, text) in files { |
@@ -251,8 +245,8 @@ impl WorldState { | |||
251 | self.analysis_host.apply_change(change); | 245 | self.analysis_host.apply_change(change); |
252 | } | 246 | } |
253 | 247 | ||
254 | pub fn snapshot(&self) -> WorldSnapshot { | 248 | pub fn snapshot(&self) -> GlobalStateSnapshot { |
255 | WorldSnapshot { | 249 | GlobalStateSnapshot { |
256 | config: self.config.clone(), | 250 | config: self.config.clone(), |
257 | workspaces: Arc::clone(&self.workspaces), | 251 | workspaces: Arc::clone(&self.workspaces), |
258 | analysis: self.analysis_host.analysis(), | 252 | analysis: self.analysis_host.analysis(), |
@@ -275,7 +269,7 @@ impl WorldState { | |||
275 | } | 269 | } |
276 | } | 270 | } |
277 | 271 | ||
278 | impl WorldSnapshot { | 272 | impl GlobalStateSnapshot { |
279 | pub fn analysis(&self) -> &Analysis { | 273 | pub fn analysis(&self) -> &Analysis { |
280 | &self.analysis | 274 | &self.analysis |
281 | } | 275 | } |
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 57d0e9218..609cb69d3 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -26,7 +26,7 @@ mod main_loop; | |||
26 | mod markdown; | 26 | mod markdown; |
27 | pub mod lsp_ext; | 27 | pub mod lsp_ext; |
28 | pub mod config; | 28 | pub mod config; |
29 | mod world; | 29 | mod global_state; |
30 | mod diagnostics; | 30 | mod diagnostics; |
31 | mod semantic_tokens; | 31 | mod semantic_tokens; |
32 | 32 | ||
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index acb1dacb6..1371f6cb4 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf}; | |||
4 | 4 | ||
5 | use lsp_types::request::Request; | 5 | use lsp_types::request::Request; |
6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; | 6 | use lsp_types::{Position, Range, TextDocumentIdentifier}; |
7 | use rustc_hash::FxHashMap; | ||
8 | use serde::{Deserialize, Serialize}; | 7 | use serde::{Deserialize, Serialize}; |
9 | 8 | ||
10 | pub enum AnalyzerStatus {} | 9 | pub enum AnalyzerStatus {} |
@@ -98,6 +97,22 @@ pub struct JoinLinesParams { | |||
98 | pub ranges: Vec<Range>, | 97 | pub ranges: Vec<Range>, |
99 | } | 98 | } |
100 | 99 | ||
100 | pub enum ResolveCodeActionRequest {} | ||
101 | |||
102 | impl Request for ResolveCodeActionRequest { | ||
103 | type Params = ResolveCodeActionParams; | ||
104 | type Result = Option<SnippetWorkspaceEdit>; | ||
105 | const METHOD: &'static str = "experimental/resolveCodeAction"; | ||
106 | } | ||
107 | |||
108 | /// Params for the ResolveCodeActionRequest | ||
109 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] | ||
110 | #[serde(rename_all = "camelCase")] | ||
111 | pub struct ResolveCodeActionParams { | ||
112 | pub code_action_params: lsp_types::CodeActionParams, | ||
113 | pub id: String, | ||
114 | } | ||
115 | |||
101 | pub enum OnEnter {} | 116 | pub enum OnEnter {} |
102 | 117 | ||
103 | impl Request for OnEnter { | 118 | impl Request for OnEnter { |
@@ -111,7 +126,7 @@ pub enum Runnables {} | |||
111 | impl Request for Runnables { | 126 | impl Request for Runnables { |
112 | type Params = RunnablesParams; | 127 | type Params = RunnablesParams; |
113 | type Result = Vec<Runnable>; | 128 | type Result = Vec<Runnable>; |
114 | const METHOD: &'static str = "rust-analyzer/runnables"; | 129 | const METHOD: &'static str = "experimental/runnables"; |
115 | } | 130 | } |
116 | 131 | ||
117 | #[derive(Serialize, Deserialize, Debug)] | 132 | #[derive(Serialize, Deserialize, Debug)] |
@@ -124,13 +139,28 @@ pub struct RunnablesParams { | |||
124 | #[derive(Deserialize, Serialize, Debug)] | 139 | #[derive(Deserialize, Serialize, Debug)] |
125 | #[serde(rename_all = "camelCase")] | 140 | #[serde(rename_all = "camelCase")] |
126 | pub struct Runnable { | 141 | pub struct Runnable { |
127 | pub range: Range, | ||
128 | pub label: String, | 142 | pub label: String, |
129 | pub bin: String, | 143 | #[serde(skip_serializing_if = "Option::is_none")] |
130 | pub args: Vec<String>, | 144 | pub location: Option<lsp_types::LocationLink>, |
131 | pub extra_args: Vec<String>, | 145 | pub kind: RunnableKind, |
132 | pub env: FxHashMap<String, String>, | 146 | pub args: CargoRunnable, |
133 | pub cwd: Option<PathBuf>, | 147 | } |
148 | |||
149 | #[derive(Serialize, Deserialize, Debug)] | ||
150 | #[serde(rename_all = "lowercase")] | ||
151 | pub enum RunnableKind { | ||
152 | Cargo, | ||
153 | } | ||
154 | |||
155 | #[derive(Deserialize, Serialize, Debug)] | ||
156 | #[serde(rename_all = "camelCase")] | ||
157 | pub struct CargoRunnable { | ||
158 | #[serde(skip_serializing_if = "Option::is_none")] | ||
159 | pub workspace_root: Option<PathBuf>, | ||
160 | // command, --package and --lib stuff | ||
161 | pub cargo_args: Vec<String>, | ||
162 | // stuff after -- | ||
163 | pub executable_args: Vec<String>, | ||
134 | } | 164 | } |
135 | 165 | ||
136 | pub enum InlayHints {} | 166 | pub enum InlayHints {} |
@@ -188,6 +218,8 @@ impl Request for CodeActionRequest { | |||
188 | pub struct CodeAction { | 218 | pub struct CodeAction { |
189 | pub title: String, | 219 | pub title: String, |
190 | #[serde(skip_serializing_if = "Option::is_none")] | 220 | #[serde(skip_serializing_if = "Option::is_none")] |
221 | pub id: Option<String>, | ||
222 | #[serde(skip_serializing_if = "Option::is_none")] | ||
191 | pub group: Option<String>, | 223 | pub group: Option<String>, |
192 | #[serde(skip_serializing_if = "Option::is_none")] | 224 | #[serde(skip_serializing_if = "Option::is_none")] |
193 | pub kind: Option<String>, | 225 | pub kind: Option<String>, |
@@ -228,3 +260,35 @@ pub struct SnippetTextEdit { | |||
228 | #[serde(skip_serializing_if = "Option::is_none")] | 260 | #[serde(skip_serializing_if = "Option::is_none")] |
229 | pub insert_text_format: Option<lsp_types::InsertTextFormat>, | 261 | pub insert_text_format: Option<lsp_types::InsertTextFormat>, |
230 | } | 262 | } |
263 | |||
264 | pub enum HoverRequest {} | ||
265 | |||
266 | impl Request for HoverRequest { | ||
267 | type Params = lsp_types::HoverParams; | ||
268 | type Result = Option<Hover>; | ||
269 | const METHOD: &'static str = "textDocument/hover"; | ||
270 | } | ||
271 | |||
272 | #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] | ||
273 | pub struct Hover { | ||
274 | #[serde(flatten)] | ||
275 | pub hover: lsp_types::Hover, | ||
276 | #[serde(skip_serializing_if = "Vec::is_empty")] | ||
277 | pub actions: Vec<CommandLinkGroup>, | ||
278 | } | ||
279 | |||
280 | #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] | ||
281 | pub struct CommandLinkGroup { | ||
282 | #[serde(skip_serializing_if = "Option::is_none")] | ||
283 | pub title: Option<String>, | ||
284 | pub commands: Vec<CommandLink>, | ||
285 | } | ||
286 | |||
287 | // LSP v3.15 Command does not have a `tooltip` field, vscode supports one. | ||
288 | #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] | ||
289 | pub struct CommandLink { | ||
290 | #[serde(flatten)] | ||
291 | pub command: lsp_types::Command, | ||
292 | #[serde(skip_serializing_if = "Option::is_none")] | ||
293 | pub tooltip: Option<String>, | ||
294 | } | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f1287d52c..752dbf145 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -12,13 +12,11 @@ use std::{ | |||
12 | fmt, | 12 | fmt, |
13 | ops::Range, | 13 | ops::Range, |
14 | panic, | 14 | panic, |
15 | path::PathBuf, | ||
16 | sync::Arc, | 15 | sync::Arc, |
17 | time::{Duration, Instant}, | 16 | time::{Duration, Instant}, |
18 | }; | 17 | }; |
19 | 18 | ||
20 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; | 19 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; |
21 | use itertools::Itertools; | ||
22 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 20 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
23 | use lsp_types::{ | 21 | use lsp_types::{ |
24 | DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, | 22 | DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, |
@@ -36,14 +34,15 @@ use serde::{de::DeserializeOwned, Serialize}; | |||
36 | use threadpool::ThreadPool; | 34 | use threadpool::ThreadPool; |
37 | 35 | ||
38 | use crate::{ | 36 | use crate::{ |
39 | config::{Config, FilesWatcher}, | 37 | config::{Config, FilesWatcher, LinkedProject}, |
40 | diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, | 38 | diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, |
41 | from_proto, lsp_ext, | 39 | from_proto, |
40 | global_state::{GlobalState, GlobalStateSnapshot}, | ||
41 | lsp_ext, | ||
42 | main_loop::{ | 42 | main_loop::{ |
43 | pending_requests::{PendingRequest, PendingRequests}, | 43 | pending_requests::{PendingRequest, PendingRequests}, |
44 | subscriptions::Subscriptions, | 44 | subscriptions::Subscriptions, |
45 | }, | 45 | }, |
46 | world::{WorldSnapshot, WorldState}, | ||
47 | Result, | 46 | Result, |
48 | }; | 47 | }; |
49 | 48 | ||
@@ -69,7 +68,7 @@ impl fmt::Display for LspError { | |||
69 | 68 | ||
70 | impl Error for LspError {} | 69 | impl Error for LspError {} |
71 | 70 | ||
72 | pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) -> Result<()> { | 71 | pub fn main_loop(config: Config, connection: Connection) -> Result<()> { |
73 | log::info!("initial config: {:#?}", config); | 72 | log::info!("initial config: {:#?}", config); |
74 | 73 | ||
75 | // Windows scheduler implements priority boosts: if thread waits for an | 74 | // Windows scheduler implements priority boosts: if thread waits for an |
@@ -92,43 +91,37 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
92 | } | 91 | } |
93 | 92 | ||
94 | let mut loop_state = LoopState::default(); | 93 | let mut loop_state = LoopState::default(); |
95 | let mut world_state = { | 94 | let mut global_state = { |
96 | let workspaces = { | 95 | let workspaces = { |
97 | // FIXME: support dynamic workspace loading. | 96 | if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { |
98 | let project_roots: FxHashSet<_> = ws_roots | ||
99 | .iter() | ||
100 | .filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok()) | ||
101 | .flatten() | ||
102 | .collect(); | ||
103 | |||
104 | if project_roots.is_empty() && config.notifications.cargo_toml_not_found { | ||
105 | show_message( | 97 | show_message( |
106 | lsp_types::MessageType::Error, | 98 | lsp_types::MessageType::Error, |
107 | format!( | 99 | "rust-analyzer failed to discover workspace".to_string(), |
108 | "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}", | ||
109 | ws_roots.iter().format_with(", ", |it, f| f(&it.display())) | ||
110 | ), | ||
111 | &connection.sender, | 100 | &connection.sender, |
112 | ); | 101 | ); |
113 | }; | 102 | }; |
114 | 103 | ||
115 | project_roots | 104 | config |
116 | .into_iter() | 105 | .linked_projects |
117 | .filter_map(|root| { | 106 | .iter() |
118 | ra_project_model::ProjectWorkspace::load( | 107 | .filter_map(|project| match project { |
119 | root, | 108 | LinkedProject::ProjectManifest(manifest) => { |
120 | &config.cargo, | 109 | ra_project_model::ProjectWorkspace::load( |
121 | config.with_sysroot, | 110 | manifest.clone(), |
122 | ) | 111 | &config.cargo, |
123 | .map_err(|err| { | 112 | config.with_sysroot, |
124 | log::error!("failed to load workspace: {:#}", err); | 113 | ) |
125 | show_message( | 114 | .map_err(|err| { |
126 | lsp_types::MessageType::Error, | 115 | log::error!("failed to load workspace: {:#}", err); |
127 | format!("rust-analyzer failed to load workspace: {:#}", err), | 116 | show_message( |
128 | &connection.sender, | 117 | lsp_types::MessageType::Error, |
129 | ); | 118 | format!("rust-analyzer failed to load workspace: {:#}", err), |
130 | }) | 119 | &connection.sender, |
131 | .ok() | 120 | ); |
121 | }) | ||
122 | .ok() | ||
123 | } | ||
124 | LinkedProject::JsonProject(it) => Some(it.clone().into()), | ||
132 | }) | 125 | }) |
133 | .collect::<Vec<_>>() | 126 | .collect::<Vec<_>>() |
134 | }; | 127 | }; |
@@ -163,8 +156,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
163 | connection.sender.send(request.into()).unwrap(); | 156 | connection.sender.send(request.into()).unwrap(); |
164 | } | 157 | } |
165 | 158 | ||
166 | WorldState::new( | 159 | GlobalState::new( |
167 | ws_roots, | ||
168 | workspaces, | 160 | workspaces, |
169 | config.lru_capacity, | 161 | config.lru_capacity, |
170 | &globs, | 162 | &globs, |
@@ -173,7 +165,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
173 | ) | 165 | ) |
174 | }; | 166 | }; |
175 | 167 | ||
176 | loop_state.roots_total = world_state.vfs.read().n_roots(); | 168 | loop_state.roots_total = global_state.vfs.read().n_roots(); |
177 | 169 | ||
178 | let pool = ThreadPool::default(); | 170 | let pool = ThreadPool::default(); |
179 | let (task_sender, task_receiver) = unbounded::<Task>(); | 171 | let (task_sender, task_receiver) = unbounded::<Task>(); |
@@ -191,12 +183,12 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
191 | Err(RecvError) => return Err("client exited without shutdown".into()), | 183 | Err(RecvError) => return Err("client exited without shutdown".into()), |
192 | }, | 184 | }, |
193 | recv(task_receiver) -> task => Event::Task(task.unwrap()), | 185 | recv(task_receiver) -> task => Event::Task(task.unwrap()), |
194 | recv(world_state.task_receiver) -> task => match task { | 186 | recv(global_state.task_receiver) -> task => match task { |
195 | Ok(task) => Event::Vfs(task), | 187 | Ok(task) => Event::Vfs(task), |
196 | Err(RecvError) => return Err("vfs died".into()), | 188 | Err(RecvError) => return Err("vfs died".into()), |
197 | }, | 189 | }, |
198 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()), | 190 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()), |
199 | recv(world_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { | 191 | recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { |
200 | Ok(task) => Event::CheckWatcher(task), | 192 | Ok(task) => Event::CheckWatcher(task), |
201 | Err(RecvError) => return Err("check watcher died".into()), | 193 | Err(RecvError) => return Err("check watcher died".into()), |
202 | } | 194 | } |
@@ -211,16 +203,16 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
211 | &task_sender, | 203 | &task_sender, |
212 | &libdata_sender, | 204 | &libdata_sender, |
213 | &connection, | 205 | &connection, |
214 | &mut world_state, | 206 | &mut global_state, |
215 | &mut loop_state, | 207 | &mut loop_state, |
216 | event, | 208 | event, |
217 | )?; | 209 | )?; |
218 | } | 210 | } |
219 | } | 211 | } |
220 | world_state.analysis_host.request_cancellation(); | 212 | global_state.analysis_host.request_cancellation(); |
221 | log::info!("waiting for tasks to finish..."); | 213 | log::info!("waiting for tasks to finish..."); |
222 | task_receiver.into_iter().for_each(|task| { | 214 | task_receiver.into_iter().for_each(|task| { |
223 | on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) | 215 | on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state) |
224 | }); | 216 | }); |
225 | libdata_receiver.into_iter().for_each(drop); | 217 | libdata_receiver.into_iter().for_each(drop); |
226 | log::info!("...tasks have finished"); | 218 | log::info!("...tasks have finished"); |
@@ -229,7 +221,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) | |||
229 | drop(pool); | 221 | drop(pool); |
230 | log::info!("...threadpool has finished"); | 222 | log::info!("...threadpool has finished"); |
231 | 223 | ||
232 | let vfs = Arc::try_unwrap(world_state.vfs).expect("all snapshots should be dead"); | 224 | let vfs = Arc::try_unwrap(global_state.vfs).expect("all snapshots should be dead"); |
233 | drop(vfs); | 225 | drop(vfs); |
234 | 226 | ||
235 | Ok(()) | 227 | Ok(()) |
@@ -320,7 +312,7 @@ fn loop_turn( | |||
320 | task_sender: &Sender<Task>, | 312 | task_sender: &Sender<Task>, |
321 | libdata_sender: &Sender<LibraryData>, | 313 | libdata_sender: &Sender<LibraryData>, |
322 | connection: &Connection, | 314 | connection: &Connection, |
323 | world_state: &mut WorldState, | 315 | global_state: &mut GlobalState, |
324 | loop_state: &mut LoopState, | 316 | loop_state: &mut LoopState, |
325 | event: Event, | 317 | event: Event, |
326 | ) -> Result<()> { | 318 | ) -> Result<()> { |
@@ -336,22 +328,22 @@ fn loop_turn( | |||
336 | 328 | ||
337 | match event { | 329 | match event { |
338 | Event::Task(task) => { | 330 | Event::Task(task) => { |
339 | on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); | 331 | on_task(task, &connection.sender, &mut loop_state.pending_requests, global_state); |
340 | world_state.maybe_collect_garbage(); | 332 | global_state.maybe_collect_garbage(); |
341 | } | 333 | } |
342 | Event::Vfs(task) => { | 334 | Event::Vfs(task) => { |
343 | world_state.vfs.write().handle_task(task); | 335 | global_state.vfs.write().handle_task(task); |
344 | } | 336 | } |
345 | Event::Lib(lib) => { | 337 | Event::Lib(lib) => { |
346 | world_state.add_lib(lib); | 338 | global_state.add_lib(lib); |
347 | world_state.maybe_collect_garbage(); | 339 | global_state.maybe_collect_garbage(); |
348 | loop_state.in_flight_libraries -= 1; | 340 | loop_state.in_flight_libraries -= 1; |
349 | loop_state.roots_scanned += 1; | 341 | loop_state.roots_scanned += 1; |
350 | } | 342 | } |
351 | Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, | 343 | Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?, |
352 | Event::Msg(msg) => match msg { | 344 | Event::Msg(msg) => match msg { |
353 | Message::Request(req) => on_request( | 345 | Message::Request(req) => on_request( |
354 | world_state, | 346 | global_state, |
355 | &mut loop_state.pending_requests, | 347 | &mut loop_state.pending_requests, |
356 | pool, | 348 | pool, |
357 | task_sender, | 349 | task_sender, |
@@ -360,7 +352,7 @@ fn loop_turn( | |||
360 | req, | 352 | req, |
361 | )?, | 353 | )?, |
362 | Message::Notification(not) => { | 354 | Message::Notification(not) => { |
363 | on_notification(&connection.sender, world_state, loop_state, not)?; | 355 | on_notification(&connection.sender, global_state, loop_state, not)?; |
364 | } | 356 | } |
365 | Message::Response(resp) => { | 357 | Message::Response(resp) => { |
366 | let removed = loop_state.pending_responses.remove(&resp.id); | 358 | let removed = loop_state.pending_responses.remove(&resp.id); |
@@ -379,9 +371,9 @@ fn loop_turn( | |||
379 | } | 371 | } |
380 | (None, Some(configs)) => { | 372 | (None, Some(configs)) => { |
381 | if let Some(new_config) = configs.get(0) { | 373 | if let Some(new_config) = configs.get(0) { |
382 | let mut config = world_state.config.clone(); | 374 | let mut config = global_state.config.clone(); |
383 | config.update(&new_config); | 375 | config.update(&new_config); |
384 | world_state.update_configuration(config); | 376 | global_state.update_configuration(config); |
385 | } | 377 | } |
386 | } | 378 | } |
387 | (None, None) => { | 379 | (None, None) => { |
@@ -394,7 +386,7 @@ fn loop_turn( | |||
394 | }; | 386 | }; |
395 | 387 | ||
396 | let mut state_changed = false; | 388 | let mut state_changed = false; |
397 | if let Some(changes) = world_state.process_changes(&mut loop_state.roots_scanned) { | 389 | if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) { |
398 | state_changed = true; | 390 | state_changed = true; |
399 | loop_state.pending_libraries.extend(changes); | 391 | loop_state.pending_libraries.extend(changes); |
400 | } | 392 | } |
@@ -416,7 +408,7 @@ fn loop_turn( | |||
416 | } | 408 | } |
417 | 409 | ||
418 | let show_progress = | 410 | let show_progress = |
419 | !loop_state.workspace_loaded && world_state.config.client_caps.work_done_progress; | 411 | !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress; |
420 | 412 | ||
421 | if !loop_state.workspace_loaded | 413 | if !loop_state.workspace_loaded |
422 | && loop_state.roots_scanned == loop_state.roots_total | 414 | && loop_state.roots_scanned == loop_state.roots_total |
@@ -425,7 +417,7 @@ fn loop_turn( | |||
425 | { | 417 | { |
426 | state_changed = true; | 418 | state_changed = true; |
427 | loop_state.workspace_loaded = true; | 419 | loop_state.workspace_loaded = true; |
428 | if let Some(flycheck) = &world_state.flycheck { | 420 | if let Some(flycheck) = &global_state.flycheck { |
429 | flycheck.update(); | 421 | flycheck.update(); |
430 | } | 422 | } |
431 | } | 423 | } |
@@ -437,13 +429,13 @@ fn loop_turn( | |||
437 | if state_changed && loop_state.workspace_loaded { | 429 | if state_changed && loop_state.workspace_loaded { |
438 | update_file_notifications_on_threadpool( | 430 | update_file_notifications_on_threadpool( |
439 | pool, | 431 | pool, |
440 | world_state.snapshot(), | 432 | global_state.snapshot(), |
441 | task_sender.clone(), | 433 | task_sender.clone(), |
442 | loop_state.subscriptions.subscriptions(), | 434 | loop_state.subscriptions.subscriptions(), |
443 | ); | 435 | ); |
444 | pool.execute({ | 436 | pool.execute({ |
445 | let subs = loop_state.subscriptions.subscriptions(); | 437 | let subs = loop_state.subscriptions.subscriptions(); |
446 | let snap = world_state.snapshot(); | 438 | let snap = global_state.snapshot(); |
447 | move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) | 439 | move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) |
448 | }); | 440 | }); |
449 | } | 441 | } |
@@ -467,7 +459,7 @@ fn on_task( | |||
467 | task: Task, | 459 | task: Task, |
468 | msg_sender: &Sender<Message>, | 460 | msg_sender: &Sender<Message>, |
469 | pending_requests: &mut PendingRequests, | 461 | pending_requests: &mut PendingRequests, |
470 | state: &mut WorldState, | 462 | state: &mut GlobalState, |
471 | ) { | 463 | ) { |
472 | match task { | 464 | match task { |
473 | Task::Respond(response) => { | 465 | Task::Respond(response) => { |
@@ -485,7 +477,7 @@ fn on_task( | |||
485 | } | 477 | } |
486 | 478 | ||
487 | fn on_request( | 479 | fn on_request( |
488 | world: &mut WorldState, | 480 | global_state: &mut GlobalState, |
489 | pending_requests: &mut PendingRequests, | 481 | pending_requests: &mut PendingRequests, |
490 | pool: &ThreadPool, | 482 | pool: &ThreadPool, |
491 | task_sender: &Sender<Task>, | 483 | task_sender: &Sender<Task>, |
@@ -496,7 +488,7 @@ fn on_request( | |||
496 | let mut pool_dispatcher = PoolDispatcher { | 488 | let mut pool_dispatcher = PoolDispatcher { |
497 | req: Some(req), | 489 | req: Some(req), |
498 | pool, | 490 | pool, |
499 | world, | 491 | global_state, |
500 | task_sender, | 492 | task_sender, |
501 | msg_sender, | 493 | msg_sender, |
502 | pending_requests, | 494 | pending_requests, |
@@ -517,6 +509,8 @@ fn on_request( | |||
517 | .on::<lsp_ext::Runnables>(handlers::handle_runnables)? | 509 | .on::<lsp_ext::Runnables>(handlers::handle_runnables)? |
518 | .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)? | 510 | .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)? |
519 | .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)? | 511 | .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)? |
512 | .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)? | ||
513 | .on::<lsp_ext::HoverRequest>(handlers::handle_hover)? | ||
520 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)? | 514 | .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)? |
521 | .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)? | 515 | .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)? |
522 | .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)? | 516 | .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)? |
@@ -528,7 +522,6 @@ fn on_request( | |||
528 | .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)? | 522 | .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)? |
529 | .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)? | 523 | .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)? |
530 | .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)? | 524 | .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)? |
531 | .on::<lsp_types::request::HoverRequest>(handlers::handle_hover)? | ||
532 | .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)? | 525 | .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)? |
533 | .on::<lsp_types::request::Rename>(handlers::handle_rename)? | 526 | .on::<lsp_types::request::Rename>(handlers::handle_rename)? |
534 | .on::<lsp_types::request::References>(handlers::handle_references)? | 527 | .on::<lsp_types::request::References>(handlers::handle_references)? |
@@ -552,7 +545,7 @@ fn on_request( | |||
552 | 545 | ||
553 | fn on_notification( | 546 | fn on_notification( |
554 | msg_sender: &Sender<Message>, | 547 | msg_sender: &Sender<Message>, |
555 | state: &mut WorldState, | 548 | state: &mut GlobalState, |
556 | loop_state: &mut LoopState, | 549 | loop_state: &mut LoopState, |
557 | not: Notification, | 550 | not: Notification, |
558 | ) -> Result<()> { | 551 | ) -> Result<()> { |
@@ -726,7 +719,7 @@ fn apply_document_changes( | |||
726 | 719 | ||
727 | fn on_check_task( | 720 | fn on_check_task( |
728 | task: CheckTask, | 721 | task: CheckTask, |
729 | world_state: &mut WorldState, | 722 | global_state: &mut GlobalState, |
730 | task_sender: &Sender<Task>, | 723 | task_sender: &Sender<Task>, |
731 | ) -> Result<()> { | 724 | ) -> Result<()> { |
732 | match task { | 725 | match task { |
@@ -745,7 +738,7 @@ fn on_check_task( | |||
745 | .uri | 738 | .uri |
746 | .to_file_path() | 739 | .to_file_path() |
747 | .map_err(|()| format!("invalid uri: {}", diag.location.uri))?; | 740 | .map_err(|()| format!("invalid uri: {}", diag.location.uri))?; |
748 | let file_id = match world_state.vfs.read().path2file(&path) { | 741 | let file_id = match global_state.vfs.read().path2file(&path) { |
749 | Some(file) => FileId(file.0), | 742 | Some(file) => FileId(file.0), |
750 | None => { | 743 | None => { |
751 | log::error!( | 744 | log::error!( |
@@ -765,7 +758,7 @@ fn on_check_task( | |||
765 | } | 758 | } |
766 | 759 | ||
767 | CheckTask::Status(status) => { | 760 | CheckTask::Status(status) => { |
768 | if world_state.config.client_caps.work_done_progress { | 761 | if global_state.config.client_caps.work_done_progress { |
769 | let progress = match status { | 762 | let progress = match status { |
770 | Status::Being => { | 763 | Status::Being => { |
771 | lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { | 764 | lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { |
@@ -804,7 +797,7 @@ fn on_check_task( | |||
804 | Ok(()) | 797 | Ok(()) |
805 | } | 798 | } |
806 | 799 | ||
807 | fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut WorldState) { | 800 | fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut GlobalState) { |
808 | let subscriptions = state.diagnostics.handle_task(task); | 801 | let subscriptions = state.diagnostics.handle_task(task); |
809 | 802 | ||
810 | for file_id in subscriptions { | 803 | for file_id in subscriptions { |
@@ -879,7 +872,7 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) { | |||
879 | struct PoolDispatcher<'a> { | 872 | struct PoolDispatcher<'a> { |
880 | req: Option<Request>, | 873 | req: Option<Request>, |
881 | pool: &'a ThreadPool, | 874 | pool: &'a ThreadPool, |
882 | world: &'a mut WorldState, | 875 | global_state: &'a mut GlobalState, |
883 | pending_requests: &'a mut PendingRequests, | 876 | pending_requests: &'a mut PendingRequests, |
884 | msg_sender: &'a Sender<Message>, | 877 | msg_sender: &'a Sender<Message>, |
885 | task_sender: &'a Sender<Task>, | 878 | task_sender: &'a Sender<Task>, |
@@ -890,7 +883,7 @@ impl<'a> PoolDispatcher<'a> { | |||
890 | /// Dispatches the request onto the current thread | 883 | /// Dispatches the request onto the current thread |
891 | fn on_sync<R>( | 884 | fn on_sync<R>( |
892 | &mut self, | 885 | &mut self, |
893 | f: fn(&mut WorldState, R::Params) -> Result<R::Result>, | 886 | f: fn(&mut GlobalState, R::Params) -> Result<R::Result>, |
894 | ) -> Result<&mut Self> | 887 | ) -> Result<&mut Self> |
895 | where | 888 | where |
896 | R: lsp_types::request::Request + 'static, | 889 | R: lsp_types::request::Request + 'static, |
@@ -903,18 +896,21 @@ impl<'a> PoolDispatcher<'a> { | |||
903 | return Ok(self); | 896 | return Ok(self); |
904 | } | 897 | } |
905 | }; | 898 | }; |
906 | let world = panic::AssertUnwindSafe(&mut *self.world); | 899 | let world = panic::AssertUnwindSafe(&mut *self.global_state); |
907 | let task = panic::catch_unwind(move || { | 900 | let task = panic::catch_unwind(move || { |
908 | let result = f(world.0, params); | 901 | let result = f(world.0, params); |
909 | result_to_task::<R>(id, result) | 902 | result_to_task::<R>(id, result) |
910 | }) | 903 | }) |
911 | .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; | 904 | .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; |
912 | on_task(task, self.msg_sender, self.pending_requests, self.world); | 905 | on_task(task, self.msg_sender, self.pending_requests, self.global_state); |
913 | Ok(self) | 906 | Ok(self) |
914 | } | 907 | } |
915 | 908 | ||
916 | /// Dispatches the request onto thread pool | 909 | /// Dispatches the request onto thread pool |
917 | fn on<R>(&mut self, f: fn(WorldSnapshot, R::Params) -> Result<R::Result>) -> Result<&mut Self> | 910 | fn on<R>( |
911 | &mut self, | ||
912 | f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, | ||
913 | ) -> Result<&mut Self> | ||
918 | where | 914 | where |
919 | R: lsp_types::request::Request + 'static, | 915 | R: lsp_types::request::Request + 'static, |
920 | R::Params: DeserializeOwned + Send + 'static, | 916 | R::Params: DeserializeOwned + Send + 'static, |
@@ -928,7 +924,7 @@ impl<'a> PoolDispatcher<'a> { | |||
928 | }; | 924 | }; |
929 | 925 | ||
930 | self.pool.execute({ | 926 | self.pool.execute({ |
931 | let world = self.world.snapshot(); | 927 | let world = self.global_state.snapshot(); |
932 | let sender = self.task_sender.clone(); | 928 | let sender = self.task_sender.clone(); |
933 | move || { | 929 | move || { |
934 | let result = f(world, params); | 930 | let result = f(world, params); |
@@ -1012,7 +1008,7 @@ where | |||
1012 | 1008 | ||
1013 | fn update_file_notifications_on_threadpool( | 1009 | fn update_file_notifications_on_threadpool( |
1014 | pool: &ThreadPool, | 1010 | pool: &ThreadPool, |
1015 | world: WorldSnapshot, | 1011 | world: GlobalStateSnapshot, |
1016 | task_sender: Sender<Task>, | 1012 | task_sender: Sender<Task>, |
1017 | subscriptions: Vec<FileId>, | 1013 | subscriptions: Vec<FileId>, |
1018 | ) { | 1014 | ) { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 1f910ff82..a41adf8b0 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -12,40 +12,37 @@ use lsp_types::{ | |||
12 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 12 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
13 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 13 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
14 | CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, | 14 | CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, |
15 | DocumentSymbol, FoldingRange, FoldingRangeParams, Hover, HoverContents, Location, | 15 | DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent, |
16 | MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, | 16 | MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, |
17 | SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, | 17 | SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, |
18 | SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, Url, WorkspaceEdit, | 18 | TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_cfg::CfgExpr; | ||
21 | use ra_ide::{ | 20 | use ra_ide::{ |
22 | FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, | 21 | FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, |
23 | TextEdit, | 22 | SearchScope, TextEdit, |
24 | }; | 23 | }; |
25 | use ra_prof::profile; | 24 | use ra_prof::profile; |
26 | use ra_project_model::TargetKind; | 25 | use ra_project_model::TargetKind; |
27 | use ra_syntax::{AstNode, SmolStr, SyntaxKind, TextRange, TextSize}; | 26 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; |
28 | use rustc_hash::FxHashMap; | ||
29 | use serde::{Deserialize, Serialize}; | 27 | use serde::{Deserialize, Serialize}; |
30 | use serde_json::to_value; | 28 | use serde_json::to_value; |
31 | use stdx::format_to; | 29 | use stdx::{format_to, split1}; |
32 | 30 | ||
33 | use crate::{ | 31 | use crate::{ |
34 | cargo_target_spec::CargoTargetSpec, | 32 | cargo_target_spec::CargoTargetSpec, |
35 | config::RustfmtConfig, | 33 | config::RustfmtConfig, |
36 | diagnostics::DiagnosticTask, | 34 | diagnostics::DiagnosticTask, |
37 | from_json, from_proto, | 35 | from_json, from_proto, |
36 | global_state::GlobalStateSnapshot, | ||
38 | lsp_ext::{self, InlayHint, InlayHintsParams}, | 37 | lsp_ext::{self, InlayHint, InlayHintsParams}, |
39 | to_proto, | 38 | to_proto, LspError, Result, |
40 | world::WorldSnapshot, | ||
41 | LspError, Result, | ||
42 | }; | 39 | }; |
43 | 40 | ||
44 | pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { | 41 | pub fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result<String> { |
45 | let _p = profile("handle_analyzer_status"); | 42 | let _p = profile("handle_analyzer_status"); |
46 | let mut buf = world.status(); | 43 | let mut buf = snap.status(); |
47 | format_to!(buf, "\n\nrequests:\n"); | 44 | format_to!(buf, "\n\nrequests:\n"); |
48 | let requests = world.latest_requests.read(); | 45 | let requests = snap.latest_requests.read(); |
49 | for (is_last, r) in requests.iter() { | 46 | for (is_last, r) in requests.iter() { |
50 | let mark = if is_last { "*" } else { " " }; | 47 | let mark = if is_last { "*" } else { " " }; |
51 | format_to!(buf, "{}{:4} {:<36}{}ms\n", mark, r.id, r.method, r.duration.as_millis()); | 48 | format_to!(buf, "{}{:4} {:<36}{}ms\n", mark, r.id, r.method, r.duration.as_millis()); |
@@ -54,37 +51,37 @@ pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { | |||
54 | } | 51 | } |
55 | 52 | ||
56 | pub fn handle_syntax_tree( | 53 | pub fn handle_syntax_tree( |
57 | world: WorldSnapshot, | 54 | snap: GlobalStateSnapshot, |
58 | params: lsp_ext::SyntaxTreeParams, | 55 | params: lsp_ext::SyntaxTreeParams, |
59 | ) -> Result<String> { | 56 | ) -> Result<String> { |
60 | let _p = profile("handle_syntax_tree"); | 57 | let _p = profile("handle_syntax_tree"); |
61 | let id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 58 | let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
62 | let line_index = world.analysis().file_line_index(id)?; | 59 | let line_index = snap.analysis().file_line_index(id)?; |
63 | let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); | 60 | let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); |
64 | let res = world.analysis().syntax_tree(id, text_range)?; | 61 | let res = snap.analysis().syntax_tree(id, text_range)?; |
65 | Ok(res) | 62 | Ok(res) |
66 | } | 63 | } |
67 | 64 | ||
68 | pub fn handle_expand_macro( | 65 | pub fn handle_expand_macro( |
69 | world: WorldSnapshot, | 66 | snap: GlobalStateSnapshot, |
70 | params: lsp_ext::ExpandMacroParams, | 67 | params: lsp_ext::ExpandMacroParams, |
71 | ) -> Result<Option<lsp_ext::ExpandedMacro>> { | 68 | ) -> Result<Option<lsp_ext::ExpandedMacro>> { |
72 | let _p = profile("handle_expand_macro"); | 69 | let _p = profile("handle_expand_macro"); |
73 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 70 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
74 | let line_index = world.analysis().file_line_index(file_id)?; | 71 | let line_index = snap.analysis().file_line_index(file_id)?; |
75 | let offset = from_proto::offset(&line_index, params.position); | 72 | let offset = from_proto::offset(&line_index, params.position); |
76 | 73 | ||
77 | let res = world.analysis().expand_macro(FilePosition { file_id, offset })?; | 74 | let res = snap.analysis().expand_macro(FilePosition { file_id, offset })?; |
78 | Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) | 75 | Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) |
79 | } | 76 | } |
80 | 77 | ||
81 | pub fn handle_selection_range( | 78 | pub fn handle_selection_range( |
82 | world: WorldSnapshot, | 79 | snap: GlobalStateSnapshot, |
83 | params: lsp_types::SelectionRangeParams, | 80 | params: lsp_types::SelectionRangeParams, |
84 | ) -> Result<Option<Vec<lsp_types::SelectionRange>>> { | 81 | ) -> Result<Option<Vec<lsp_types::SelectionRange>>> { |
85 | let _p = profile("handle_selection_range"); | 82 | let _p = profile("handle_selection_range"); |
86 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 83 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
87 | let line_index = world.analysis().file_line_index(file_id)?; | 84 | let line_index = snap.analysis().file_line_index(file_id)?; |
88 | let res: Result<Vec<lsp_types::SelectionRange>> = params | 85 | let res: Result<Vec<lsp_types::SelectionRange>> = params |
89 | .positions | 86 | .positions |
90 | .into_iter() | 87 | .into_iter() |
@@ -96,7 +93,7 @@ pub fn handle_selection_range( | |||
96 | loop { | 93 | loop { |
97 | ranges.push(range); | 94 | ranges.push(range); |
98 | let frange = FileRange { file_id, range }; | 95 | let frange = FileRange { file_id, range }; |
99 | let next = world.analysis().extend_selection(frange)?; | 96 | let next = snap.analysis().extend_selection(frange)?; |
100 | if next == range { | 97 | if next == range { |
101 | break; | 98 | break; |
102 | } else { | 99 | } else { |
@@ -122,18 +119,18 @@ pub fn handle_selection_range( | |||
122 | } | 119 | } |
123 | 120 | ||
124 | pub fn handle_matching_brace( | 121 | pub fn handle_matching_brace( |
125 | world: WorldSnapshot, | 122 | snap: GlobalStateSnapshot, |
126 | params: lsp_ext::MatchingBraceParams, | 123 | params: lsp_ext::MatchingBraceParams, |
127 | ) -> Result<Vec<Position>> { | 124 | ) -> Result<Vec<Position>> { |
128 | let _p = profile("handle_matching_brace"); | 125 | let _p = profile("handle_matching_brace"); |
129 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 126 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
130 | let line_index = world.analysis().file_line_index(file_id)?; | 127 | let line_index = snap.analysis().file_line_index(file_id)?; |
131 | let res = params | 128 | let res = params |
132 | .positions | 129 | .positions |
133 | .into_iter() | 130 | .into_iter() |
134 | .map(|position| { | 131 | .map(|position| { |
135 | let offset = from_proto::offset(&line_index, position); | 132 | let offset = from_proto::offset(&line_index, position); |
136 | let offset = match world.analysis().matching_brace(FilePosition { file_id, offset }) { | 133 | let offset = match snap.analysis().matching_brace(FilePosition { file_id, offset }) { |
137 | Ok(Some(matching_brace_offset)) => matching_brace_offset, | 134 | Ok(Some(matching_brace_offset)) => matching_brace_offset, |
138 | Err(_) | Ok(None) => offset, | 135 | Err(_) | Ok(None) => offset, |
139 | }; | 136 | }; |
@@ -144,17 +141,17 @@ pub fn handle_matching_brace( | |||
144 | } | 141 | } |
145 | 142 | ||
146 | pub fn handle_join_lines( | 143 | pub fn handle_join_lines( |
147 | world: WorldSnapshot, | 144 | snap: GlobalStateSnapshot, |
148 | params: lsp_ext::JoinLinesParams, | 145 | params: lsp_ext::JoinLinesParams, |
149 | ) -> Result<Vec<lsp_types::TextEdit>> { | 146 | ) -> Result<Vec<lsp_types::TextEdit>> { |
150 | let _p = profile("handle_join_lines"); | 147 | let _p = profile("handle_join_lines"); |
151 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 148 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
152 | let line_index = world.analysis().file_line_index(file_id)?; | 149 | let line_index = snap.analysis().file_line_index(file_id)?; |
153 | let line_endings = world.file_line_endings(file_id); | 150 | let line_endings = snap.file_line_endings(file_id); |
154 | let mut res = TextEdit::default(); | 151 | let mut res = TextEdit::default(); |
155 | for range in params.ranges { | 152 | for range in params.ranges { |
156 | let range = from_proto::text_range(&line_index, range); | 153 | let range = from_proto::text_range(&line_index, range); |
157 | let edit = world.analysis().join_lines(FileRange { file_id, range })?; | 154 | let edit = snap.analysis().join_lines(FileRange { file_id, range })?; |
158 | match res.union(edit) { | 155 | match res.union(edit) { |
159 | Ok(()) => (), | 156 | Ok(()) => (), |
160 | Err(_edit) => { | 157 | Err(_edit) => { |
@@ -167,37 +164,37 @@ pub fn handle_join_lines( | |||
167 | } | 164 | } |
168 | 165 | ||
169 | pub fn handle_on_enter( | 166 | pub fn handle_on_enter( |
170 | world: WorldSnapshot, | 167 | snap: GlobalStateSnapshot, |
171 | params: lsp_types::TextDocumentPositionParams, | 168 | params: lsp_types::TextDocumentPositionParams, |
172 | ) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> { | 169 | ) -> Result<Option<Vec<lsp_ext::SnippetTextEdit>>> { |
173 | let _p = profile("handle_on_enter"); | 170 | let _p = profile("handle_on_enter"); |
174 | let position = from_proto::file_position(&world, params)?; | 171 | let position = from_proto::file_position(&snap, params)?; |
175 | let edit = match world.analysis().on_enter(position)? { | 172 | let edit = match snap.analysis().on_enter(position)? { |
176 | None => return Ok(None), | 173 | None => return Ok(None), |
177 | Some(it) => it, | 174 | Some(it) => it, |
178 | }; | 175 | }; |
179 | let line_index = world.analysis().file_line_index(position.file_id)?; | 176 | let line_index = snap.analysis().file_line_index(position.file_id)?; |
180 | let line_endings = world.file_line_endings(position.file_id); | 177 | let line_endings = snap.file_line_endings(position.file_id); |
181 | let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); | 178 | let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); |
182 | Ok(Some(edit)) | 179 | Ok(Some(edit)) |
183 | } | 180 | } |
184 | 181 | ||
185 | // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. | 182 | // Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. |
186 | pub fn handle_on_type_formatting( | 183 | pub fn handle_on_type_formatting( |
187 | world: WorldSnapshot, | 184 | snap: GlobalStateSnapshot, |
188 | params: lsp_types::DocumentOnTypeFormattingParams, | 185 | params: lsp_types::DocumentOnTypeFormattingParams, |
189 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { | 186 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
190 | let _p = profile("handle_on_type_formatting"); | 187 | let _p = profile("handle_on_type_formatting"); |
191 | let mut position = from_proto::file_position(&world, params.text_document_position)?; | 188 | let mut position = from_proto::file_position(&snap, params.text_document_position)?; |
192 | let line_index = world.analysis().file_line_index(position.file_id)?; | 189 | let line_index = snap.analysis().file_line_index(position.file_id)?; |
193 | let line_endings = world.file_line_endings(position.file_id); | 190 | let line_endings = snap.file_line_endings(position.file_id); |
194 | 191 | ||
195 | // in `ra_ide`, the `on_type` invariant is that | 192 | // in `ra_ide`, the `on_type` invariant is that |
196 | // `text.char_at(position) == typed_char`. | 193 | // `text.char_at(position) == typed_char`. |
197 | position.offset -= TextSize::of('.'); | 194 | position.offset -= TextSize::of('.'); |
198 | let char_typed = params.ch.chars().next().unwrap_or('\0'); | 195 | let char_typed = params.ch.chars().next().unwrap_or('\0'); |
199 | assert!({ | 196 | assert!({ |
200 | let text = world.analysis().file_text(position.file_id)?; | 197 | let text = snap.analysis().file_text(position.file_id)?; |
201 | text[usize::from(position.offset)..].starts_with(char_typed) | 198 | text[usize::from(position.offset)..].starts_with(char_typed) |
202 | }); | 199 | }); |
203 | 200 | ||
@@ -209,7 +206,7 @@ pub fn handle_on_type_formatting( | |||
209 | return Ok(None); | 206 | return Ok(None); |
210 | } | 207 | } |
211 | 208 | ||
212 | let edit = world.analysis().on_char_typed(position, char_typed)?; | 209 | let edit = snap.analysis().on_char_typed(position, char_typed)?; |
213 | let mut edit = match edit { | 210 | let mut edit = match edit { |
214 | Some(it) => it, | 211 | Some(it) => it, |
215 | None => return Ok(None), | 212 | None => return Ok(None), |
@@ -223,16 +220,16 @@ pub fn handle_on_type_formatting( | |||
223 | } | 220 | } |
224 | 221 | ||
225 | pub fn handle_document_symbol( | 222 | pub fn handle_document_symbol( |
226 | world: WorldSnapshot, | 223 | snap: GlobalStateSnapshot, |
227 | params: lsp_types::DocumentSymbolParams, | 224 | params: lsp_types::DocumentSymbolParams, |
228 | ) -> Result<Option<lsp_types::DocumentSymbolResponse>> { | 225 | ) -> Result<Option<lsp_types::DocumentSymbolResponse>> { |
229 | let _p = profile("handle_document_symbol"); | 226 | let _p = profile("handle_document_symbol"); |
230 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 227 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
231 | let line_index = world.analysis().file_line_index(file_id)?; | 228 | let line_index = snap.analysis().file_line_index(file_id)?; |
232 | 229 | ||
233 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); | 230 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); |
234 | 231 | ||
235 | for symbol in world.analysis().file_structure(file_id)? { | 232 | for symbol in snap.analysis().file_structure(file_id)? { |
236 | let doc_symbol = DocumentSymbol { | 233 | let doc_symbol = DocumentSymbol { |
237 | name: symbol.label, | 234 | name: symbol.label, |
238 | detail: symbol.detail, | 235 | detail: symbol.detail, |
@@ -258,10 +255,10 @@ pub fn handle_document_symbol( | |||
258 | } | 255 | } |
259 | } | 256 | } |
260 | 257 | ||
261 | let res = if world.config.client_caps.hierarchical_symbols { | 258 | let res = if snap.config.client_caps.hierarchical_symbols { |
262 | document_symbols.into() | 259 | document_symbols.into() |
263 | } else { | 260 | } else { |
264 | let url = to_proto::url(&world, file_id)?; | 261 | let url = to_proto::url(&snap, file_id)?; |
265 | let mut symbol_information = Vec::<SymbolInformation>::new(); | 262 | let mut symbol_information = Vec::<SymbolInformation>::new(); |
266 | for symbol in document_symbols { | 263 | for symbol in document_symbols { |
267 | flatten_document_symbol(&symbol, None, &url, &mut symbol_information); | 264 | flatten_document_symbol(&symbol, None, &url, &mut symbol_information); |
@@ -291,7 +288,7 @@ pub fn handle_document_symbol( | |||
291 | } | 288 | } |
292 | 289 | ||
293 | pub fn handle_workspace_symbol( | 290 | pub fn handle_workspace_symbol( |
294 | world: WorldSnapshot, | 291 | snap: GlobalStateSnapshot, |
295 | params: lsp_types::WorkspaceSymbolParams, | 292 | params: lsp_types::WorkspaceSymbolParams, |
296 | ) -> Result<Option<Vec<SymbolInformation>>> { | 293 | ) -> Result<Option<Vec<SymbolInformation>>> { |
297 | let _p = profile("handle_workspace_symbol"); | 294 | let _p = profile("handle_workspace_symbol"); |
@@ -309,22 +306,22 @@ pub fn handle_workspace_symbol( | |||
309 | q.limit(128); | 306 | q.limit(128); |
310 | q | 307 | q |
311 | }; | 308 | }; |
312 | let mut res = exec_query(&world, query)?; | 309 | let mut res = exec_query(&snap, query)?; |
313 | if res.is_empty() && !all_symbols { | 310 | if res.is_empty() && !all_symbols { |
314 | let mut query = Query::new(params.query); | 311 | let mut query = Query::new(params.query); |
315 | query.limit(128); | 312 | query.limit(128); |
316 | res = exec_query(&world, query)?; | 313 | res = exec_query(&snap, query)?; |
317 | } | 314 | } |
318 | 315 | ||
319 | return Ok(Some(res)); | 316 | return Ok(Some(res)); |
320 | 317 | ||
321 | fn exec_query(world: &WorldSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { | 318 | fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { |
322 | let mut res = Vec::new(); | 319 | let mut res = Vec::new(); |
323 | for nav in world.analysis().symbol_search(query)? { | 320 | for nav in snap.analysis().symbol_search(query)? { |
324 | let info = SymbolInformation { | 321 | let info = SymbolInformation { |
325 | name: nav.name().to_string(), | 322 | name: nav.name().to_string(), |
326 | kind: to_proto::symbol_kind(nav.kind()), | 323 | kind: to_proto::symbol_kind(nav.kind()), |
327 | location: to_proto::location(world, nav.file_range())?, | 324 | location: to_proto::location(snap, nav.file_range())?, |
328 | container_name: nav.container_name().map(|v| v.to_string()), | 325 | container_name: nav.container_name().map(|v| v.to_string()), |
329 | deprecated: None, | 326 | deprecated: None, |
330 | }; | 327 | }; |
@@ -335,88 +332,83 @@ pub fn handle_workspace_symbol( | |||
335 | } | 332 | } |
336 | 333 | ||
337 | pub fn handle_goto_definition( | 334 | pub fn handle_goto_definition( |
338 | world: WorldSnapshot, | 335 | snap: GlobalStateSnapshot, |
339 | params: lsp_types::GotoDefinitionParams, | 336 | params: lsp_types::GotoDefinitionParams, |
340 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { | 337 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { |
341 | let _p = profile("handle_goto_definition"); | 338 | let _p = profile("handle_goto_definition"); |
342 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 339 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
343 | let nav_info = match world.analysis().goto_definition(position)? { | 340 | let nav_info = match snap.analysis().goto_definition(position)? { |
344 | None => return Ok(None), | 341 | None => return Ok(None), |
345 | Some(it) => it, | 342 | Some(it) => it, |
346 | }; | 343 | }; |
347 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; | 344 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
348 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; | 345 | let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; |
349 | Ok(Some(res)) | 346 | Ok(Some(res)) |
350 | } | 347 | } |
351 | 348 | ||
352 | pub fn handle_goto_implementation( | 349 | pub fn handle_goto_implementation( |
353 | world: WorldSnapshot, | 350 | snap: GlobalStateSnapshot, |
354 | params: lsp_types::request::GotoImplementationParams, | 351 | params: lsp_types::request::GotoImplementationParams, |
355 | ) -> Result<Option<lsp_types::request::GotoImplementationResponse>> { | 352 | ) -> Result<Option<lsp_types::request::GotoImplementationResponse>> { |
356 | let _p = profile("handle_goto_implementation"); | 353 | let _p = profile("handle_goto_implementation"); |
357 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 354 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
358 | let nav_info = match world.analysis().goto_implementation(position)? { | 355 | let nav_info = match snap.analysis().goto_implementation(position)? { |
359 | None => return Ok(None), | 356 | None => return Ok(None), |
360 | Some(it) => it, | 357 | Some(it) => it, |
361 | }; | 358 | }; |
362 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; | 359 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
363 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; | 360 | let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; |
364 | Ok(Some(res)) | 361 | Ok(Some(res)) |
365 | } | 362 | } |
366 | 363 | ||
367 | pub fn handle_goto_type_definition( | 364 | pub fn handle_goto_type_definition( |
368 | world: WorldSnapshot, | 365 | snap: GlobalStateSnapshot, |
369 | params: lsp_types::request::GotoTypeDefinitionParams, | 366 | params: lsp_types::request::GotoTypeDefinitionParams, |
370 | ) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> { | 367 | ) -> Result<Option<lsp_types::request::GotoTypeDefinitionResponse>> { |
371 | let _p = profile("handle_goto_type_definition"); | 368 | let _p = profile("handle_goto_type_definition"); |
372 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 369 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
373 | let nav_info = match world.analysis().goto_type_definition(position)? { | 370 | let nav_info = match snap.analysis().goto_type_definition(position)? { |
374 | None => return Ok(None), | 371 | None => return Ok(None), |
375 | Some(it) => it, | 372 | Some(it) => it, |
376 | }; | 373 | }; |
377 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; | 374 | let src = FileRange { file_id: position.file_id, range: nav_info.range }; |
378 | let res = to_proto::goto_definition_response(&world, Some(src), nav_info.info)?; | 375 | let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; |
379 | Ok(Some(res)) | 376 | Ok(Some(res)) |
380 | } | 377 | } |
381 | 378 | ||
382 | pub fn handle_parent_module( | 379 | pub fn handle_parent_module( |
383 | world: WorldSnapshot, | 380 | snap: GlobalStateSnapshot, |
384 | params: lsp_types::TextDocumentPositionParams, | 381 | params: lsp_types::TextDocumentPositionParams, |
385 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { | 382 | ) -> Result<Option<lsp_types::GotoDefinitionResponse>> { |
386 | let _p = profile("handle_parent_module"); | 383 | let _p = profile("handle_parent_module"); |
387 | let position = from_proto::file_position(&world, params)?; | 384 | let position = from_proto::file_position(&snap, params)?; |
388 | let navs = world.analysis().parent_module(position)?; | 385 | let navs = snap.analysis().parent_module(position)?; |
389 | let res = to_proto::goto_definition_response(&world, None, navs)?; | 386 | let res = to_proto::goto_definition_response(&snap, None, navs)?; |
390 | Ok(Some(res)) | 387 | Ok(Some(res)) |
391 | } | 388 | } |
392 | 389 | ||
393 | pub fn handle_runnables( | 390 | pub fn handle_runnables( |
394 | world: WorldSnapshot, | 391 | snap: GlobalStateSnapshot, |
395 | params: lsp_ext::RunnablesParams, | 392 | params: lsp_ext::RunnablesParams, |
396 | ) -> Result<Vec<lsp_ext::Runnable>> { | 393 | ) -> Result<Vec<lsp_ext::Runnable>> { |
397 | let _p = profile("handle_runnables"); | 394 | let _p = profile("handle_runnables"); |
398 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 395 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
399 | let line_index = world.analysis().file_line_index(file_id)?; | 396 | let line_index = snap.analysis().file_line_index(file_id)?; |
400 | let offset = params.position.map(|it| from_proto::offset(&line_index, it)); | 397 | let offset = params.position.map(|it| from_proto::offset(&line_index, it)); |
401 | let mut res = Vec::new(); | 398 | let mut res = Vec::new(); |
402 | let workspace_root = world.workspace_root_for(file_id); | 399 | let workspace_root = snap.workspace_root_for(file_id); |
403 | let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; | 400 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; |
404 | for runnable in world.analysis().runnables(file_id)? { | 401 | for runnable in snap.analysis().runnables(file_id)? { |
405 | if let Some(offset) = offset { | 402 | if let Some(offset) = offset { |
406 | if !runnable.range.contains_inclusive(offset) { | 403 | if !runnable.nav.full_range().contains_inclusive(offset) { |
407 | continue; | 404 | continue; |
408 | } | 405 | } |
409 | } | 406 | } |
410 | // Do not suggest binary run on other target than binary | 407 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
411 | if let RunnableKind::Bin = runnable.kind { | 408 | continue; |
412 | if let Some(spec) = &cargo_spec { | ||
413 | match spec.target_kind { | ||
414 | TargetKind::Bin => {} | ||
415 | _ => continue, | ||
416 | } | ||
417 | } | ||
418 | } | 409 | } |
419 | res.push(to_lsp_runnable(&world, file_id, runnable)?); | 410 | |
411 | res.push(to_proto::runnable(&snap, file_id, runnable)?); | ||
420 | } | 412 | } |
421 | 413 | ||
422 | // Add `cargo check` and `cargo test` for the whole package | 414 | // Add `cargo check` and `cargo test` for the whole package |
@@ -424,25 +416,31 @@ pub fn handle_runnables( | |||
424 | Some(spec) => { | 416 | Some(spec) => { |
425 | for &cmd in ["check", "test"].iter() { | 417 | for &cmd in ["check", "test"].iter() { |
426 | res.push(lsp_ext::Runnable { | 418 | res.push(lsp_ext::Runnable { |
427 | range: Default::default(), | ||
428 | label: format!("cargo {} -p {}", cmd, spec.package), | 419 | label: format!("cargo {} -p {}", cmd, spec.package), |
429 | bin: "cargo".to_string(), | 420 | location: None, |
430 | args: vec![cmd.to_string(), "--package".to_string(), spec.package.clone()], | 421 | kind: lsp_ext::RunnableKind::Cargo, |
431 | extra_args: Vec::new(), | 422 | args: lsp_ext::CargoRunnable { |
432 | env: FxHashMap::default(), | 423 | workspace_root: workspace_root.map(|root| root.to_owned()), |
433 | cwd: workspace_root.map(|root| root.to_owned()), | 424 | cargo_args: vec![ |
425 | cmd.to_string(), | ||
426 | "--package".to_string(), | ||
427 | spec.package.clone(), | ||
428 | ], | ||
429 | executable_args: Vec::new(), | ||
430 | }, | ||
434 | }) | 431 | }) |
435 | } | 432 | } |
436 | } | 433 | } |
437 | None => { | 434 | None => { |
438 | res.push(lsp_ext::Runnable { | 435 | res.push(lsp_ext::Runnable { |
439 | range: Default::default(), | ||
440 | label: "cargo check --workspace".to_string(), | 436 | label: "cargo check --workspace".to_string(), |
441 | bin: "cargo".to_string(), | 437 | location: None, |
442 | args: vec!["check".to_string(), "--workspace".to_string()], | 438 | kind: lsp_ext::RunnableKind::Cargo, |
443 | extra_args: Vec::new(), | 439 | args: lsp_ext::CargoRunnable { |
444 | env: FxHashMap::default(), | 440 | workspace_root: workspace_root.map(|root| root.to_owned()), |
445 | cwd: workspace_root.map(|root| root.to_owned()), | 441 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], |
442 | executable_args: Vec::new(), | ||
443 | }, | ||
446 | }); | 444 | }); |
447 | } | 445 | } |
448 | } | 446 | } |
@@ -450,16 +448,16 @@ pub fn handle_runnables( | |||
450 | } | 448 | } |
451 | 449 | ||
452 | pub fn handle_completion( | 450 | pub fn handle_completion( |
453 | world: WorldSnapshot, | 451 | snap: GlobalStateSnapshot, |
454 | params: lsp_types::CompletionParams, | 452 | params: lsp_types::CompletionParams, |
455 | ) -> Result<Option<lsp_types::CompletionResponse>> { | 453 | ) -> Result<Option<lsp_types::CompletionResponse>> { |
456 | let _p = profile("handle_completion"); | 454 | let _p = profile("handle_completion"); |
457 | let position = from_proto::file_position(&world, params.text_document_position)?; | 455 | let position = from_proto::file_position(&snap, params.text_document_position)?; |
458 | let completion_triggered_after_single_colon = { | 456 | let completion_triggered_after_single_colon = { |
459 | let mut res = false; | 457 | let mut res = false; |
460 | if let Some(ctx) = params.context { | 458 | if let Some(ctx) = params.context { |
461 | if ctx.trigger_character.unwrap_or_default() == ":" { | 459 | if ctx.trigger_character.unwrap_or_default() == ":" { |
462 | let source_file = world.analysis().parse(position.file_id)?; | 460 | let source_file = snap.analysis().parse(position.file_id)?; |
463 | let syntax = source_file.syntax(); | 461 | let syntax = source_file.syntax(); |
464 | let text = syntax.text(); | 462 | let text = syntax.text(); |
465 | if let Some(next_char) = text.char_at(position.offset) { | 463 | if let Some(next_char) = text.char_at(position.offset) { |
@@ -477,12 +475,12 @@ pub fn handle_completion( | |||
477 | return Ok(None); | 475 | return Ok(None); |
478 | } | 476 | } |
479 | 477 | ||
480 | let items = match world.analysis().completions(&world.config.completion, position)? { | 478 | let items = match snap.analysis().completions(&snap.config.completion, position)? { |
481 | None => return Ok(None), | 479 | None => return Ok(None), |
482 | Some(items) => items, | 480 | Some(items) => items, |
483 | }; | 481 | }; |
484 | let line_index = world.analysis().file_line_index(position.file_id)?; | 482 | let line_index = snap.analysis().file_line_index(position.file_id)?; |
485 | let line_endings = world.file_line_endings(position.file_id); | 483 | let line_endings = snap.file_line_endings(position.file_id); |
486 | let items: Vec<CompletionItem> = items | 484 | let items: Vec<CompletionItem> = items |
487 | .into_iter() | 485 | .into_iter() |
488 | .map(|item| to_proto::completion_item(&line_index, line_endings, item)) | 486 | .map(|item| to_proto::completion_item(&line_index, line_endings, item)) |
@@ -492,15 +490,15 @@ pub fn handle_completion( | |||
492 | } | 490 | } |
493 | 491 | ||
494 | pub fn handle_folding_range( | 492 | pub fn handle_folding_range( |
495 | world: WorldSnapshot, | 493 | snap: GlobalStateSnapshot, |
496 | params: FoldingRangeParams, | 494 | params: FoldingRangeParams, |
497 | ) -> Result<Option<Vec<FoldingRange>>> { | 495 | ) -> Result<Option<Vec<FoldingRange>>> { |
498 | let _p = profile("handle_folding_range"); | 496 | let _p = profile("handle_folding_range"); |
499 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 497 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
500 | let folds = world.analysis().folding_ranges(file_id)?; | 498 | let folds = snap.analysis().folding_ranges(file_id)?; |
501 | let text = world.analysis().file_text(file_id)?; | 499 | let text = snap.analysis().file_text(file_id)?; |
502 | let line_index = world.analysis().file_line_index(file_id)?; | 500 | let line_index = snap.analysis().file_line_index(file_id)?; |
503 | let line_folding_only = world.config.client_caps.line_folding_only; | 501 | let line_folding_only = snap.config.client_caps.line_folding_only; |
504 | let res = folds | 502 | let res = folds |
505 | .into_iter() | 503 | .into_iter() |
506 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) | 504 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) |
@@ -509,16 +507,16 @@ pub fn handle_folding_range( | |||
509 | } | 507 | } |
510 | 508 | ||
511 | pub fn handle_signature_help( | 509 | pub fn handle_signature_help( |
512 | world: WorldSnapshot, | 510 | snap: GlobalStateSnapshot, |
513 | params: lsp_types::SignatureHelpParams, | 511 | params: lsp_types::SignatureHelpParams, |
514 | ) -> Result<Option<lsp_types::SignatureHelp>> { | 512 | ) -> Result<Option<lsp_types::SignatureHelp>> { |
515 | let _p = profile("handle_signature_help"); | 513 | let _p = profile("handle_signature_help"); |
516 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 514 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
517 | let call_info = match world.analysis().call_info(position)? { | 515 | let call_info = match snap.analysis().call_info(position)? { |
518 | None => return Ok(None), | 516 | None => return Ok(None), |
519 | Some(it) => it, | 517 | Some(it) => it, |
520 | }; | 518 | }; |
521 | let concise = !world.config.call_info_full; | 519 | let concise = !snap.config.call_info_full; |
522 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); | 520 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); |
523 | if concise && call_info.signature.has_self_param { | 521 | if concise && call_info.signature.has_self_param { |
524 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); | 522 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); |
@@ -532,46 +530,56 @@ pub fn handle_signature_help( | |||
532 | })) | 530 | })) |
533 | } | 531 | } |
534 | 532 | ||
535 | pub fn handle_hover(world: WorldSnapshot, params: lsp_types::HoverParams) -> Result<Option<Hover>> { | 533 | pub fn handle_hover( |
534 | snap: GlobalStateSnapshot, | ||
535 | params: lsp_types::HoverParams, | ||
536 | ) -> Result<Option<lsp_ext::Hover>> { | ||
536 | let _p = profile("handle_hover"); | 537 | let _p = profile("handle_hover"); |
537 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 538 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
538 | let info = match world.analysis().hover(position)? { | 539 | let info = match snap.analysis().hover(position)? { |
539 | None => return Ok(None), | 540 | None => return Ok(None), |
540 | Some(info) => info, | 541 | Some(info) => info, |
541 | }; | 542 | }; |
542 | let line_index = world.analysis.file_line_index(position.file_id)?; | 543 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
543 | let range = to_proto::range(&line_index, info.range); | 544 | let range = to_proto::range(&line_index, info.range); |
544 | let res = Hover { | 545 | let hover = lsp_ext::Hover { |
545 | contents: HoverContents::Markup(MarkupContent { | 546 | hover: lsp_types::Hover { |
546 | kind: MarkupKind::Markdown, | 547 | contents: HoverContents::Markup(MarkupContent { |
547 | value: crate::markdown::format_docs(&info.info.to_markup()), | 548 | kind: MarkupKind::Markdown, |
548 | }), | 549 | value: crate::markdown::format_docs(&info.info.to_markup()), |
549 | range: Some(range), | 550 | }), |
551 | range: Some(range), | ||
552 | }, | ||
553 | actions: prepare_hover_actions(&snap, position.file_id, info.info.actions()), | ||
550 | }; | 554 | }; |
551 | Ok(Some(res)) | 555 | |
556 | Ok(Some(hover)) | ||
552 | } | 557 | } |
553 | 558 | ||
554 | pub fn handle_prepare_rename( | 559 | pub fn handle_prepare_rename( |
555 | world: WorldSnapshot, | 560 | snap: GlobalStateSnapshot, |
556 | params: lsp_types::TextDocumentPositionParams, | 561 | params: lsp_types::TextDocumentPositionParams, |
557 | ) -> Result<Option<PrepareRenameResponse>> { | 562 | ) -> Result<Option<PrepareRenameResponse>> { |
558 | let _p = profile("handle_prepare_rename"); | 563 | let _p = profile("handle_prepare_rename"); |
559 | let position = from_proto::file_position(&world, params)?; | 564 | let position = from_proto::file_position(&snap, params)?; |
560 | 565 | ||
561 | let optional_change = world.analysis().rename(position, "dummy")?; | 566 | let optional_change = snap.analysis().rename(position, "dummy")?; |
562 | let range = match optional_change { | 567 | let range = match optional_change { |
563 | None => return Ok(None), | 568 | None => return Ok(None), |
564 | Some(it) => it.range, | 569 | Some(it) => it.range, |
565 | }; | 570 | }; |
566 | 571 | ||
567 | let line_index = world.analysis().file_line_index(position.file_id)?; | 572 | let line_index = snap.analysis().file_line_index(position.file_id)?; |
568 | let range = to_proto::range(&line_index, range); | 573 | let range = to_proto::range(&line_index, range); |
569 | Ok(Some(PrepareRenameResponse::Range(range))) | 574 | Ok(Some(PrepareRenameResponse::Range(range))) |
570 | } | 575 | } |
571 | 576 | ||
572 | pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> { | 577 | pub fn handle_rename( |
578 | snap: GlobalStateSnapshot, | ||
579 | params: RenameParams, | ||
580 | ) -> Result<Option<WorkspaceEdit>> { | ||
573 | let _p = profile("handle_rename"); | 581 | let _p = profile("handle_rename"); |
574 | let position = from_proto::file_position(&world, params.text_document_position)?; | 582 | let position = from_proto::file_position(&snap, params.text_document_position)?; |
575 | 583 | ||
576 | if params.new_name.is_empty() { | 584 | if params.new_name.is_empty() { |
577 | return Err(LspError::new( | 585 | return Err(LspError::new( |
@@ -581,36 +589,36 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Optio | |||
581 | .into()); | 589 | .into()); |
582 | } | 590 | } |
583 | 591 | ||
584 | let optional_change = world.analysis().rename(position, &*params.new_name)?; | 592 | let optional_change = snap.analysis().rename(position, &*params.new_name)?; |
585 | let source_change = match optional_change { | 593 | let source_change = match optional_change { |
586 | None => return Ok(None), | 594 | None => return Ok(None), |
587 | Some(it) => it.info, | 595 | Some(it) => it.info, |
588 | }; | 596 | }; |
589 | let workspace_edit = to_proto::workspace_edit(&world, source_change)?; | 597 | let workspace_edit = to_proto::workspace_edit(&snap, source_change)?; |
590 | Ok(Some(workspace_edit)) | 598 | Ok(Some(workspace_edit)) |
591 | } | 599 | } |
592 | 600 | ||
593 | pub fn handle_references( | 601 | pub fn handle_references( |
594 | world: WorldSnapshot, | 602 | snap: GlobalStateSnapshot, |
595 | params: lsp_types::ReferenceParams, | 603 | params: lsp_types::ReferenceParams, |
596 | ) -> Result<Option<Vec<Location>>> { | 604 | ) -> Result<Option<Vec<Location>>> { |
597 | let _p = profile("handle_references"); | 605 | let _p = profile("handle_references"); |
598 | let position = from_proto::file_position(&world, params.text_document_position)?; | 606 | let position = from_proto::file_position(&snap, params.text_document_position)?; |
599 | 607 | ||
600 | let refs = match world.analysis().find_all_refs(position, None)? { | 608 | let refs = match snap.analysis().find_all_refs(position, None)? { |
601 | None => return Ok(None), | 609 | None => return Ok(None), |
602 | Some(refs) => refs, | 610 | Some(refs) => refs, |
603 | }; | 611 | }; |
604 | 612 | ||
605 | let locations = if params.context.include_declaration { | 613 | let locations = if params.context.include_declaration { |
606 | refs.into_iter() | 614 | refs.into_iter() |
607 | .filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) | 615 | .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) |
608 | .collect() | 616 | .collect() |
609 | } else { | 617 | } else { |
610 | // Only iterate over the references if include_declaration was false | 618 | // Only iterate over the references if include_declaration was false |
611 | refs.references() | 619 | refs.references() |
612 | .iter() | 620 | .iter() |
613 | .filter_map(|reference| to_proto::location(&world, reference.file_range).ok()) | 621 | .filter_map(|reference| to_proto::location(&snap, reference.file_range).ok()) |
614 | .collect() | 622 | .collect() |
615 | }; | 623 | }; |
616 | 624 | ||
@@ -618,24 +626,24 @@ pub fn handle_references( | |||
618 | } | 626 | } |
619 | 627 | ||
620 | pub fn handle_formatting( | 628 | pub fn handle_formatting( |
621 | world: WorldSnapshot, | 629 | snap: GlobalStateSnapshot, |
622 | params: DocumentFormattingParams, | 630 | params: DocumentFormattingParams, |
623 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { | 631 | ) -> Result<Option<Vec<lsp_types::TextEdit>>> { |
624 | let _p = profile("handle_formatting"); | 632 | let _p = profile("handle_formatting"); |
625 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 633 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
626 | let file = world.analysis().file_text(file_id)?; | 634 | let file = snap.analysis().file_text(file_id)?; |
627 | let crate_ids = world.analysis().crate_for(file_id)?; | 635 | let crate_ids = snap.analysis().crate_for(file_id)?; |
628 | 636 | ||
629 | let file_line_index = world.analysis().file_line_index(file_id)?; | 637 | let file_line_index = snap.analysis().file_line_index(file_id)?; |
630 | let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); | 638 | let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); |
631 | 639 | ||
632 | let mut rustfmt = match &world.config.rustfmt { | 640 | let mut rustfmt = match &snap.config.rustfmt { |
633 | RustfmtConfig::Rustfmt { extra_args } => { | 641 | RustfmtConfig::Rustfmt { extra_args } => { |
634 | let mut cmd = process::Command::new("rustfmt"); | 642 | let mut cmd = process::Command::new("rustfmt"); |
635 | cmd.args(extra_args); | 643 | cmd.args(extra_args); |
636 | if let Some(&crate_id) = crate_ids.first() { | 644 | if let Some(&crate_id) = crate_ids.first() { |
637 | // Assume all crates are in the same edition | 645 | // Assume all crates are in the same edition |
638 | let edition = world.analysis().crate_edition(crate_id)?; | 646 | let edition = snap.analysis().crate_edition(crate_id)?; |
639 | cmd.arg("--edition"); | 647 | cmd.arg("--edition"); |
640 | cmd.arg(edition.to_string()); | 648 | cmd.arg(edition.to_string()); |
641 | } | 649 | } |
@@ -693,136 +701,145 @@ pub fn handle_formatting( | |||
693 | }])) | 701 | }])) |
694 | } | 702 | } |
695 | 703 | ||
696 | pub fn handle_code_action( | 704 | fn handle_fixes( |
697 | world: WorldSnapshot, | 705 | snap: &GlobalStateSnapshot, |
698 | params: lsp_types::CodeActionParams, | 706 | params: &lsp_types::CodeActionParams, |
699 | ) -> Result<Option<Vec<lsp_ext::CodeAction>>> { | 707 | res: &mut Vec<lsp_ext::CodeAction>, |
700 | let _p = profile("handle_code_action"); | 708 | ) -> Result<()> { |
701 | // We intentionally don't support command-based actions, as those either | 709 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
702 | // requires custom client-code anyway, or requires server-initiated edits. | 710 | let line_index = snap.analysis().file_line_index(file_id)?; |
703 | // Server initiated edits break causality, so we avoid those as well. | ||
704 | if !world.config.client_caps.code_action_literals { | ||
705 | return Ok(None); | ||
706 | } | ||
707 | |||
708 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | ||
709 | let line_index = world.analysis().file_line_index(file_id)?; | ||
710 | let range = from_proto::text_range(&line_index, params.range); | 711 | let range = from_proto::text_range(&line_index, params.range); |
711 | let frange = FileRange { file_id, range }; | 712 | let diagnostics = snap.analysis().diagnostics(file_id)?; |
712 | |||
713 | let diagnostics = world.analysis().diagnostics(file_id)?; | ||
714 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | ||
715 | 713 | ||
716 | let fixes_from_diagnostics = diagnostics | 714 | let fixes_from_diagnostics = diagnostics |
717 | .into_iter() | 715 | .into_iter() |
718 | .filter_map(|d| Some((d.range, d.fix?))) | 716 | .filter_map(|d| Some((d.range, d.fix?))) |
719 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) | 717 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) |
720 | .map(|(_range, fix)| fix); | 718 | .map(|(_range, fix)| fix); |
721 | |||
722 | for fix in fixes_from_diagnostics { | 719 | for fix in fixes_from_diagnostics { |
723 | let title = fix.label; | 720 | let title = fix.label; |
724 | let edit = to_proto::snippet_workspace_edit(&world, fix.source_change)?; | 721 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; |
725 | let action = | 722 | let action = lsp_ext::CodeAction { |
726 | lsp_ext::CodeAction { title, group: None, kind: None, edit: Some(edit), command: None }; | 723 | title, |
724 | id: None, | ||
725 | group: None, | ||
726 | kind: Some(lsp_types::code_action_kind::QUICKFIX.into()), | ||
727 | edit: Some(edit), | ||
728 | command: None, | ||
729 | }; | ||
727 | res.push(action); | 730 | res.push(action); |
728 | } | 731 | } |
729 | 732 | ||
730 | for fix in world.check_fixes.get(&file_id).into_iter().flatten() { | 733 | for fix in snap.check_fixes.get(&file_id).into_iter().flatten() { |
731 | let fix_range = from_proto::text_range(&line_index, fix.range); | 734 | let fix_range = from_proto::text_range(&line_index, fix.range); |
732 | if fix_range.intersect(range).is_none() { | 735 | if fix_range.intersect(range).is_none() { |
733 | continue; | 736 | continue; |
734 | } | 737 | } |
735 | res.push(fix.action.clone()); | 738 | res.push(fix.action.clone()); |
736 | } | 739 | } |
740 | Ok(()) | ||
741 | } | ||
737 | 742 | ||
738 | for assist in world.analysis().assists(&world.config.assist, frange)?.into_iter() { | 743 | pub fn handle_code_action( |
739 | res.push(to_proto::code_action(&world, assist)?.into()); | 744 | snap: GlobalStateSnapshot, |
745 | params: lsp_types::CodeActionParams, | ||
746 | ) -> Result<Option<Vec<lsp_ext::CodeAction>>> { | ||
747 | let _p = profile("handle_code_action"); | ||
748 | // We intentionally don't support command-based actions, as those either | ||
749 | // requires custom client-code anyway, or requires server-initiated edits. | ||
750 | // Server initiated edits break causality, so we avoid those as well. | ||
751 | if !snap.config.client_caps.code_action_literals { | ||
752 | return Ok(None); | ||
753 | } | ||
754 | |||
755 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; | ||
756 | let line_index = snap.analysis().file_line_index(file_id)?; | ||
757 | let range = from_proto::text_range(&line_index, params.range); | ||
758 | let frange = FileRange { file_id, range }; | ||
759 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | ||
760 | |||
761 | handle_fixes(&snap, ¶ms, &mut res)?; | ||
762 | |||
763 | if snap.config.client_caps.resolve_code_action { | ||
764 | for (index, assist) in | ||
765 | snap.analysis().unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() | ||
766 | { | ||
767 | res.push(to_proto::unresolved_code_action(&snap, assist, index)?); | ||
768 | } | ||
769 | } else { | ||
770 | for assist in snap.analysis().resolved_assists(&snap.config.assist, frange)?.into_iter() { | ||
771 | res.push(to_proto::resolved_code_action(&snap, assist)?); | ||
772 | } | ||
740 | } | 773 | } |
774 | |||
741 | Ok(Some(res)) | 775 | Ok(Some(res)) |
742 | } | 776 | } |
743 | 777 | ||
778 | pub fn handle_resolve_code_action( | ||
779 | snap: GlobalStateSnapshot, | ||
780 | params: lsp_ext::ResolveCodeActionParams, | ||
781 | ) -> Result<Option<lsp_ext::SnippetWorkspaceEdit>> { | ||
782 | let _p = profile("handle_resolve_code_action"); | ||
783 | let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; | ||
784 | let line_index = snap.analysis().file_line_index(file_id)?; | ||
785 | let range = from_proto::text_range(&line_index, params.code_action_params.range); | ||
786 | let frange = FileRange { file_id, range }; | ||
787 | |||
788 | let assists = snap.analysis().resolved_assists(&snap.config.assist, frange)?; | ||
789 | let (id_string, index) = split1(¶ms.id, ':').unwrap(); | ||
790 | let index = index.parse::<usize>().unwrap(); | ||
791 | let assist = &assists[index]; | ||
792 | assert!(assist.assist.id.0 == id_string); | ||
793 | Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) | ||
794 | } | ||
795 | |||
744 | pub fn handle_code_lens( | 796 | pub fn handle_code_lens( |
745 | world: WorldSnapshot, | 797 | snap: GlobalStateSnapshot, |
746 | params: lsp_types::CodeLensParams, | 798 | params: lsp_types::CodeLensParams, |
747 | ) -> Result<Option<Vec<CodeLens>>> { | 799 | ) -> Result<Option<Vec<CodeLens>>> { |
748 | let _p = profile("handle_code_lens"); | 800 | let _p = profile("handle_code_lens"); |
749 | let mut lenses: Vec<CodeLens> = Default::default(); | 801 | let mut lenses: Vec<CodeLens> = Default::default(); |
750 | 802 | ||
751 | if world.config.lens.none() { | 803 | if snap.config.lens.none() { |
752 | // early return before any db query! | 804 | // early return before any db query! |
753 | return Ok(Some(lenses)); | 805 | return Ok(Some(lenses)); |
754 | } | 806 | } |
755 | 807 | ||
756 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 808 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
757 | let line_index = world.analysis().file_line_index(file_id)?; | 809 | let line_index = snap.analysis().file_line_index(file_id)?; |
758 | let cargo_spec = CargoTargetSpec::for_file(&world, file_id)?; | 810 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; |
759 | 811 | ||
760 | if world.config.lens.runnable() { | 812 | if snap.config.lens.runnable() { |
761 | // Gather runnables | 813 | // Gather runnables |
762 | for runnable in world.analysis().runnables(file_id)? { | 814 | for runnable in snap.analysis().runnables(file_id)? { |
763 | let (run_title, debugee) = match &runnable.kind { | 815 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
764 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { | 816 | continue; |
765 | ("▶\u{fe0e} Run Test", true) | 817 | } |
766 | } | ||
767 | RunnableKind::DocTest { .. } => { | ||
768 | // cargo does not support -no-run for doctests | ||
769 | ("▶\u{fe0e} Run Doctest", false) | ||
770 | } | ||
771 | RunnableKind::Bench { .. } => { | ||
772 | // Nothing wrong with bench debugging | ||
773 | ("Run Bench", true) | ||
774 | } | ||
775 | RunnableKind::Bin => { | ||
776 | // Do not suggest binary run on other target than binary | ||
777 | match &cargo_spec { | ||
778 | Some(spec) => match spec.target_kind { | ||
779 | TargetKind::Bin => ("Run", true), | ||
780 | _ => continue, | ||
781 | }, | ||
782 | None => continue, | ||
783 | } | ||
784 | } | ||
785 | }; | ||
786 | 818 | ||
787 | let mut r = to_lsp_runnable(&world, file_id, runnable)?; | 819 | let action = runnable.action(); |
788 | if world.config.lens.run { | 820 | let range = to_proto::range(&line_index, runnable.nav.range()); |
821 | let r = to_proto::runnable(&snap, file_id, runnable)?; | ||
822 | if snap.config.lens.run { | ||
789 | let lens = CodeLens { | 823 | let lens = CodeLens { |
790 | range: r.range, | 824 | range, |
791 | command: Some(Command { | 825 | command: Some(run_single_command(&r, action.run_title)), |
792 | title: run_title.to_string(), | ||
793 | command: "rust-analyzer.runSingle".into(), | ||
794 | arguments: Some(vec![to_value(&r).unwrap()]), | ||
795 | }), | ||
796 | data: None, | 826 | data: None, |
797 | }; | 827 | }; |
798 | lenses.push(lens); | 828 | lenses.push(lens); |
799 | } | 829 | } |
800 | 830 | ||
801 | if debugee && world.config.lens.debug { | 831 | if action.debugee && snap.config.lens.debug { |
802 | if r.args[0] == "run" { | 832 | let debug_lens = |
803 | r.args[0] = "build".into(); | 833 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; |
804 | } else { | ||
805 | r.args.push("--no-run".into()); | ||
806 | } | ||
807 | let debug_lens = CodeLens { | ||
808 | range: r.range, | ||
809 | command: Some(Command { | ||
810 | title: "Debug".into(), | ||
811 | command: "rust-analyzer.debugSingle".into(), | ||
812 | arguments: Some(vec![to_value(r).unwrap()]), | ||
813 | }), | ||
814 | data: None, | ||
815 | }; | ||
816 | lenses.push(debug_lens); | 834 | lenses.push(debug_lens); |
817 | } | 835 | } |
818 | } | 836 | } |
819 | } | 837 | } |
820 | 838 | ||
821 | if world.config.lens.impementations { | 839 | if snap.config.lens.impementations { |
822 | // Handle impls | 840 | // Handle impls |
823 | lenses.extend( | 841 | lenses.extend( |
824 | world | 842 | snap.analysis() |
825 | .analysis() | ||
826 | .file_structure(file_id)? | 843 | .file_structure(file_id)? |
827 | .into_iter() | 844 | .into_iter() |
828 | .filter(|it| match it.kind { | 845 | .filter(|it| match it.kind { |
@@ -857,14 +874,17 @@ enum CodeLensResolveData { | |||
857 | Impls(lsp_types::request::GotoImplementationParams), | 874 | Impls(lsp_types::request::GotoImplementationParams), |
858 | } | 875 | } |
859 | 876 | ||
860 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { | 877 | pub fn handle_code_lens_resolve( |
878 | snap: GlobalStateSnapshot, | ||
879 | code_lens: CodeLens, | ||
880 | ) -> Result<CodeLens> { | ||
861 | let _p = profile("handle_code_lens_resolve"); | 881 | let _p = profile("handle_code_lens_resolve"); |
862 | let data = code_lens.data.unwrap(); | 882 | let data = code_lens.data.unwrap(); |
863 | let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?; | 883 | let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?; |
864 | match resolve { | 884 | match resolve { |
865 | Some(CodeLensResolveData::Impls(lens_params)) => { | 885 | Some(CodeLensResolveData::Impls(lens_params)) => { |
866 | let locations: Vec<Location> = | 886 | let locations: Vec<Location> = |
867 | match handle_goto_implementation(world, lens_params.clone())? { | 887 | match handle_goto_implementation(snap, lens_params.clone())? { |
868 | Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc], | 888 | Some(lsp_types::GotoDefinitionResponse::Scalar(loc)) => vec![loc], |
869 | Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs, | 889 | Some(lsp_types::GotoDefinitionResponse::Array(locs)) => locs, |
870 | Some(lsp_types::GotoDefinitionResponse::Link(links)) => links | 890 | Some(lsp_types::GotoDefinitionResponse::Link(links)) => links |
@@ -874,24 +894,13 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re | |||
874 | _ => vec![], | 894 | _ => vec![], |
875 | }; | 895 | }; |
876 | 896 | ||
877 | let title = if locations.len() == 1 { | 897 | let title = implementation_title(locations.len()); |
878 | "1 implementation".into() | 898 | let cmd = show_references_command( |
879 | } else { | ||
880 | format!("{} implementations", locations.len()) | ||
881 | }; | ||
882 | |||
883 | // We cannot use the 'editor.action.showReferences' command directly | ||
884 | // because that command requires vscode types which we convert in the handler | ||
885 | // on the client side. | ||
886 | let cmd = Command { | ||
887 | title, | 899 | title, |
888 | command: "rust-analyzer.showReferences".into(), | 900 | &lens_params.text_document_position_params.text_document.uri, |
889 | arguments: Some(vec![ | 901 | code_lens.range.start, |
890 | to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(), | 902 | locations, |
891 | to_value(code_lens.range.start).unwrap(), | 903 | ); |
892 | to_value(locations).unwrap(), | ||
893 | ]), | ||
894 | }; | ||
895 | Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) | 904 | Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None }) |
896 | } | 905 | } |
897 | None => Ok(CodeLens { | 906 | None => Ok(CodeLens { |
@@ -903,14 +912,14 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re | |||
903 | } | 912 | } |
904 | 913 | ||
905 | pub fn handle_document_highlight( | 914 | pub fn handle_document_highlight( |
906 | world: WorldSnapshot, | 915 | snap: GlobalStateSnapshot, |
907 | params: lsp_types::DocumentHighlightParams, | 916 | params: lsp_types::DocumentHighlightParams, |
908 | ) -> Result<Option<Vec<DocumentHighlight>>> { | 917 | ) -> Result<Option<Vec<DocumentHighlight>>> { |
909 | let _p = profile("handle_document_highlight"); | 918 | let _p = profile("handle_document_highlight"); |
910 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 919 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
911 | let line_index = world.analysis().file_line_index(position.file_id)?; | 920 | let line_index = snap.analysis().file_line_index(position.file_id)?; |
912 | 921 | ||
913 | let refs = match world | 922 | let refs = match snap |
914 | .analysis() | 923 | .analysis() |
915 | .find_all_refs(position, Some(SearchScope::single_file(position.file_id)))? | 924 | .find_all_refs(position, Some(SearchScope::single_file(position.file_id)))? |
916 | { | 925 | { |
@@ -930,19 +939,19 @@ pub fn handle_document_highlight( | |||
930 | } | 939 | } |
931 | 940 | ||
932 | pub fn handle_ssr( | 941 | pub fn handle_ssr( |
933 | world: WorldSnapshot, | 942 | snap: GlobalStateSnapshot, |
934 | params: lsp_ext::SsrParams, | 943 | params: lsp_ext::SsrParams, |
935 | ) -> Result<lsp_types::WorkspaceEdit> { | 944 | ) -> Result<lsp_types::WorkspaceEdit> { |
936 | let _p = profile("handle_ssr"); | 945 | let _p = profile("handle_ssr"); |
937 | let source_change = | 946 | let source_change = |
938 | world.analysis().structural_search_replace(¶ms.query, params.parse_only)??; | 947 | snap.analysis().structural_search_replace(¶ms.query, params.parse_only)??; |
939 | to_proto::workspace_edit(&world, source_change) | 948 | to_proto::workspace_edit(&snap, source_change) |
940 | } | 949 | } |
941 | 950 | ||
942 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { | 951 | pub fn publish_diagnostics(snap: &GlobalStateSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
943 | let _p = profile("publish_diagnostics"); | 952 | let _p = profile("publish_diagnostics"); |
944 | let line_index = world.analysis().file_line_index(file_id)?; | 953 | let line_index = snap.analysis().file_line_index(file_id)?; |
945 | let diagnostics: Vec<Diagnostic> = world | 954 | let diagnostics: Vec<Diagnostic> = snap |
946 | .analysis() | 955 | .analysis() |
947 | .diagnostics(file_id)? | 956 | .diagnostics(file_id)? |
948 | .into_iter() | 957 | .into_iter() |
@@ -959,87 +968,29 @@ pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<Dia | |||
959 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) | 968 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) |
960 | } | 969 | } |
961 | 970 | ||
962 | fn to_lsp_runnable( | ||
963 | world: &WorldSnapshot, | ||
964 | file_id: FileId, | ||
965 | runnable: Runnable, | ||
966 | ) -> Result<lsp_ext::Runnable> { | ||
967 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
968 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
969 | let mut features_needed = vec![]; | ||
970 | for cfg_expr in &runnable.cfg_exprs { | ||
971 | collect_minimal_features_needed(cfg_expr, &mut features_needed); | ||
972 | } | ||
973 | let (args, extra_args) = | ||
974 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &features_needed)?; | ||
975 | let line_index = world.analysis().file_line_index(file_id)?; | ||
976 | let label = match &runnable.kind { | ||
977 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
978 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
979 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
980 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
981 | RunnableKind::Bin => { | ||
982 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
983 | } | ||
984 | }; | ||
985 | Ok(lsp_ext::Runnable { | ||
986 | range: to_proto::range(&line_index, runnable.range), | ||
987 | label, | ||
988 | bin: "cargo".to_string(), | ||
989 | args, | ||
990 | extra_args, | ||
991 | env: { | ||
992 | let mut m = FxHashMap::default(); | ||
993 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
994 | m | ||
995 | }, | ||
996 | cwd: world.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
997 | }) | ||
998 | } | ||
999 | |||
1000 | /// Fill minimal features needed | ||
1001 | fn collect_minimal_features_needed(cfg_expr: &CfgExpr, features: &mut Vec<SmolStr>) { | ||
1002 | match cfg_expr { | ||
1003 | CfgExpr::KeyValue { key, value } if key == "feature" => features.push(value.clone()), | ||
1004 | CfgExpr::All(preds) => { | ||
1005 | preds.iter().for_each(|cfg| collect_minimal_features_needed(cfg, features)); | ||
1006 | } | ||
1007 | CfgExpr::Any(preds) => { | ||
1008 | for cfg in preds { | ||
1009 | let len_features = features.len(); | ||
1010 | collect_minimal_features_needed(cfg, features); | ||
1011 | if len_features != features.len() { | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | } | ||
1016 | _ => {} | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | pub fn handle_inlay_hints( | 971 | pub fn handle_inlay_hints( |
1021 | world: WorldSnapshot, | 972 | snap: GlobalStateSnapshot, |
1022 | params: InlayHintsParams, | 973 | params: InlayHintsParams, |
1023 | ) -> Result<Vec<InlayHint>> { | 974 | ) -> Result<Vec<InlayHint>> { |
1024 | let _p = profile("handle_inlay_hints"); | 975 | let _p = profile("handle_inlay_hints"); |
1025 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 976 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
1026 | let analysis = world.analysis(); | 977 | let analysis = snap.analysis(); |
1027 | let line_index = analysis.file_line_index(file_id)?; | 978 | let line_index = analysis.file_line_index(file_id)?; |
1028 | Ok(analysis | 979 | Ok(analysis |
1029 | .inlay_hints(file_id, &world.config.inlay_hints)? | 980 | .inlay_hints(file_id, &snap.config.inlay_hints)? |
1030 | .into_iter() | 981 | .into_iter() |
1031 | .map(|it| to_proto::inlay_int(&line_index, it)) | 982 | .map(|it| to_proto::inlay_int(&line_index, it)) |
1032 | .collect()) | 983 | .collect()) |
1033 | } | 984 | } |
1034 | 985 | ||
1035 | pub fn handle_call_hierarchy_prepare( | 986 | pub fn handle_call_hierarchy_prepare( |
1036 | world: WorldSnapshot, | 987 | snap: GlobalStateSnapshot, |
1037 | params: CallHierarchyPrepareParams, | 988 | params: CallHierarchyPrepareParams, |
1038 | ) -> Result<Option<Vec<CallHierarchyItem>>> { | 989 | ) -> Result<Option<Vec<CallHierarchyItem>>> { |
1039 | let _p = profile("handle_call_hierarchy_prepare"); | 990 | let _p = profile("handle_call_hierarchy_prepare"); |
1040 | let position = from_proto::file_position(&world, params.text_document_position_params)?; | 991 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
1041 | 992 | ||
1042 | let nav_info = match world.analysis().call_hierarchy(position)? { | 993 | let nav_info = match snap.analysis().call_hierarchy(position)? { |
1043 | None => return Ok(None), | 994 | None => return Ok(None), |
1044 | Some(it) => it, | 995 | Some(it) => it, |
1045 | }; | 996 | }; |
@@ -1048,24 +999,24 @@ pub fn handle_call_hierarchy_prepare( | |||
1048 | let res = navs | 999 | let res = navs |
1049 | .into_iter() | 1000 | .into_iter() |
1050 | .filter(|it| it.kind() == SyntaxKind::FN_DEF) | 1001 | .filter(|it| it.kind() == SyntaxKind::FN_DEF) |
1051 | .map(|it| to_proto::call_hierarchy_item(&world, it)) | 1002 | .map(|it| to_proto::call_hierarchy_item(&snap, it)) |
1052 | .collect::<Result<Vec<_>>>()?; | 1003 | .collect::<Result<Vec<_>>>()?; |
1053 | 1004 | ||
1054 | Ok(Some(res)) | 1005 | Ok(Some(res)) |
1055 | } | 1006 | } |
1056 | 1007 | ||
1057 | pub fn handle_call_hierarchy_incoming( | 1008 | pub fn handle_call_hierarchy_incoming( |
1058 | world: WorldSnapshot, | 1009 | snap: GlobalStateSnapshot, |
1059 | params: CallHierarchyIncomingCallsParams, | 1010 | params: CallHierarchyIncomingCallsParams, |
1060 | ) -> Result<Option<Vec<CallHierarchyIncomingCall>>> { | 1011 | ) -> Result<Option<Vec<CallHierarchyIncomingCall>>> { |
1061 | let _p = profile("handle_call_hierarchy_incoming"); | 1012 | let _p = profile("handle_call_hierarchy_incoming"); |
1062 | let item = params.item; | 1013 | let item = params.item; |
1063 | 1014 | ||
1064 | let doc = TextDocumentIdentifier::new(item.uri); | 1015 | let doc = TextDocumentIdentifier::new(item.uri); |
1065 | let frange = from_proto::file_range(&world, doc, item.range)?; | 1016 | let frange = from_proto::file_range(&snap, doc, item.range)?; |
1066 | let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | 1017 | let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; |
1067 | 1018 | ||
1068 | let call_items = match world.analysis().incoming_calls(fpos)? { | 1019 | let call_items = match snap.analysis().incoming_calls(fpos)? { |
1069 | None => return Ok(None), | 1020 | None => return Ok(None), |
1070 | Some(it) => it, | 1021 | Some(it) => it, |
1071 | }; | 1022 | }; |
@@ -1074,8 +1025,8 @@ pub fn handle_call_hierarchy_incoming( | |||
1074 | 1025 | ||
1075 | for call_item in call_items.into_iter() { | 1026 | for call_item in call_items.into_iter() { |
1076 | let file_id = call_item.target.file_id(); | 1027 | let file_id = call_item.target.file_id(); |
1077 | let line_index = world.analysis().file_line_index(file_id)?; | 1028 | let line_index = snap.analysis().file_line_index(file_id)?; |
1078 | let item = to_proto::call_hierarchy_item(&world, call_item.target)?; | 1029 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; |
1079 | res.push(CallHierarchyIncomingCall { | 1030 | res.push(CallHierarchyIncomingCall { |
1080 | from: item, | 1031 | from: item, |
1081 | from_ranges: call_item | 1032 | from_ranges: call_item |
@@ -1090,17 +1041,17 @@ pub fn handle_call_hierarchy_incoming( | |||
1090 | } | 1041 | } |
1091 | 1042 | ||
1092 | pub fn handle_call_hierarchy_outgoing( | 1043 | pub fn handle_call_hierarchy_outgoing( |
1093 | world: WorldSnapshot, | 1044 | snap: GlobalStateSnapshot, |
1094 | params: CallHierarchyOutgoingCallsParams, | 1045 | params: CallHierarchyOutgoingCallsParams, |
1095 | ) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> { | 1046 | ) -> Result<Option<Vec<CallHierarchyOutgoingCall>>> { |
1096 | let _p = profile("handle_call_hierarchy_outgoing"); | 1047 | let _p = profile("handle_call_hierarchy_outgoing"); |
1097 | let item = params.item; | 1048 | let item = params.item; |
1098 | 1049 | ||
1099 | let doc = TextDocumentIdentifier::new(item.uri); | 1050 | let doc = TextDocumentIdentifier::new(item.uri); |
1100 | let frange = from_proto::file_range(&world, doc, item.range)?; | 1051 | let frange = from_proto::file_range(&snap, doc, item.range)?; |
1101 | let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | 1052 | let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; |
1102 | 1053 | ||
1103 | let call_items = match world.analysis().outgoing_calls(fpos)? { | 1054 | let call_items = match snap.analysis().outgoing_calls(fpos)? { |
1104 | None => return Ok(None), | 1055 | None => return Ok(None), |
1105 | Some(it) => it, | 1056 | Some(it) => it, |
1106 | }; | 1057 | }; |
@@ -1109,8 +1060,8 @@ pub fn handle_call_hierarchy_outgoing( | |||
1109 | 1060 | ||
1110 | for call_item in call_items.into_iter() { | 1061 | for call_item in call_items.into_iter() { |
1111 | let file_id = call_item.target.file_id(); | 1062 | let file_id = call_item.target.file_id(); |
1112 | let line_index = world.analysis().file_line_index(file_id)?; | 1063 | let line_index = snap.analysis().file_line_index(file_id)?; |
1113 | let item = to_proto::call_hierarchy_item(&world, call_item.target)?; | 1064 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; |
1114 | res.push(CallHierarchyOutgoingCall { | 1065 | res.push(CallHierarchyOutgoingCall { |
1115 | to: item, | 1066 | to: item, |
1116 | from_ranges: call_item | 1067 | from_ranges: call_item |
@@ -1125,82 +1076,165 @@ pub fn handle_call_hierarchy_outgoing( | |||
1125 | } | 1076 | } |
1126 | 1077 | ||
1127 | pub fn handle_semantic_tokens( | 1078 | pub fn handle_semantic_tokens( |
1128 | world: WorldSnapshot, | 1079 | snap: GlobalStateSnapshot, |
1129 | params: SemanticTokensParams, | 1080 | params: SemanticTokensParams, |
1130 | ) -> Result<Option<SemanticTokensResult>> { | 1081 | ) -> Result<Option<SemanticTokensResult>> { |
1131 | let _p = profile("handle_semantic_tokens"); | 1082 | let _p = profile("handle_semantic_tokens"); |
1132 | 1083 | ||
1133 | let file_id = from_proto::file_id(&world, ¶ms.text_document.uri)?; | 1084 | let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; |
1134 | let text = world.analysis().file_text(file_id)?; | 1085 | let text = snap.analysis().file_text(file_id)?; |
1135 | let line_index = world.analysis().file_line_index(file_id)?; | 1086 | let line_index = snap.analysis().file_line_index(file_id)?; |
1136 | 1087 | ||
1137 | let highlights = world.analysis().highlight(file_id)?; | 1088 | let highlights = snap.analysis().highlight(file_id)?; |
1138 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); | 1089 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); |
1139 | Ok(Some(semantic_tokens.into())) | 1090 | Ok(Some(semantic_tokens.into())) |
1140 | } | 1091 | } |
1141 | 1092 | ||
1142 | pub fn handle_semantic_tokens_range( | 1093 | pub fn handle_semantic_tokens_range( |
1143 | world: WorldSnapshot, | 1094 | snap: GlobalStateSnapshot, |
1144 | params: SemanticTokensRangeParams, | 1095 | params: SemanticTokensRangeParams, |
1145 | ) -> Result<Option<SemanticTokensRangeResult>> { | 1096 | ) -> Result<Option<SemanticTokensRangeResult>> { |
1146 | let _p = profile("handle_semantic_tokens_range"); | 1097 | let _p = profile("handle_semantic_tokens_range"); |
1147 | 1098 | ||
1148 | let frange = from_proto::file_range(&world, params.text_document, params.range)?; | 1099 | let frange = from_proto::file_range(&snap, params.text_document, params.range)?; |
1149 | let text = world.analysis().file_text(frange.file_id)?; | 1100 | let text = snap.analysis().file_text(frange.file_id)?; |
1150 | let line_index = world.analysis().file_line_index(frange.file_id)?; | 1101 | let line_index = snap.analysis().file_line_index(frange.file_id)?; |
1151 | 1102 | ||
1152 | let highlights = world.analysis().highlight_range(frange)?; | 1103 | let highlights = snap.analysis().highlight_range(frange)?; |
1153 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); | 1104 | let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); |
1154 | Ok(Some(semantic_tokens.into())) | 1105 | Ok(Some(semantic_tokens.into())) |
1155 | } | 1106 | } |
1156 | 1107 | ||
1157 | #[cfg(test)] | 1108 | fn implementation_title(count: usize) -> String { |
1158 | mod tests { | 1109 | if count == 1 { |
1159 | use super::*; | 1110 | "1 implementation".into() |
1111 | } else { | ||
1112 | format!("{} implementations", count) | ||
1113 | } | ||
1114 | } | ||
1160 | 1115 | ||
1161 | use mbe::{ast_to_token_tree, TokenMap}; | 1116 | fn show_references_command( |
1162 | use ra_cfg::parse_cfg; | 1117 | title: String, |
1163 | use ra_syntax::{ | 1118 | uri: &lsp_types::Url, |
1164 | ast::{self, AstNode}, | 1119 | position: lsp_types::Position, |
1165 | SmolStr, | 1120 | locations: Vec<lsp_types::Location>, |
1166 | }; | 1121 | ) -> Command { |
1122 | // We cannot use the 'editor.action.showReferences' command directly | ||
1123 | // because that command requires vscode types which we convert in the handler | ||
1124 | // on the client side. | ||
1125 | |||
1126 | Command { | ||
1127 | title, | ||
1128 | command: "rust-analyzer.showReferences".into(), | ||
1129 | arguments: Some(vec![ | ||
1130 | to_value(uri).unwrap(), | ||
1131 | to_value(position).unwrap(), | ||
1132 | to_value(locations).unwrap(), | ||
1133 | ]), | ||
1134 | } | ||
1135 | } | ||
1167 | 1136 | ||
1168 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { | 1137 | fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command { |
1169 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | 1138 | Command { |
1170 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | 1139 | title: title.to_string(), |
1171 | ast_to_token_tree(&tt).unwrap() | 1140 | command: "rust-analyzer.runSingle".into(), |
1141 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1172 | } | 1142 | } |
1143 | } | ||
1173 | 1144 | ||
1174 | #[test] | 1145 | fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { |
1175 | fn test_cfg_expr_minimal_features_needed() { | 1146 | Command { |
1176 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#); | 1147 | title: "Debug".into(), |
1177 | let cfg_expr = parse_cfg(&subtree); | 1148 | command: "rust-analyzer.debugSingle".into(), |
1178 | let mut min_features = vec![]; | 1149 | arguments: Some(vec![to_value(runnable).unwrap()]), |
1179 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | 1150 | } |
1151 | } | ||
1180 | 1152 | ||
1181 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | 1153 | fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { |
1154 | lsp_ext::CommandLink { tooltip: Some(tooltip), command } | ||
1155 | } | ||
1182 | 1156 | ||
1183 | let (subtree, _) = | 1157 | fn show_impl_command_link( |
1184 | get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#); | 1158 | snap: &GlobalStateSnapshot, |
1185 | let cfg_expr = parse_cfg(&subtree); | 1159 | position: &FilePosition, |
1160 | ) -> Option<lsp_ext::CommandLinkGroup> { | ||
1161 | if snap.config.hover.implementations { | ||
1162 | if let Some(nav_data) = snap.analysis().goto_implementation(*position).unwrap_or(None) { | ||
1163 | let uri = to_proto::url(snap, position.file_id).ok()?; | ||
1164 | let line_index = snap.analysis().file_line_index(position.file_id).ok()?; | ||
1165 | let position = to_proto::position(&line_index, position.offset); | ||
1166 | let locations: Vec<_> = nav_data | ||
1167 | .info | ||
1168 | .iter() | ||
1169 | .filter_map(|it| to_proto::location(snap, it.file_range()).ok()) | ||
1170 | .collect(); | ||
1171 | let title = implementation_title(locations.len()); | ||
1172 | let command = show_references_command(title, &uri, position, locations); | ||
1173 | |||
1174 | return Some(lsp_ext::CommandLinkGroup { | ||
1175 | commands: vec![to_command_link(command, "Go to implementations".into())], | ||
1176 | ..Default::default() | ||
1177 | }); | ||
1178 | } | ||
1179 | } | ||
1180 | None | ||
1181 | } | ||
1186 | 1182 | ||
1187 | let mut min_features = vec![]; | 1183 | fn to_runnable_action( |
1188 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | 1184 | snap: &GlobalStateSnapshot, |
1189 | assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]); | 1185 | file_id: FileId, |
1186 | runnable: Runnable, | ||
1187 | ) -> Option<lsp_ext::CommandLinkGroup> { | ||
1188 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; | ||
1189 | if should_skip_target(&runnable, cargo_spec.as_ref()) { | ||
1190 | return None; | ||
1191 | } | ||
1190 | 1192 | ||
1191 | let (subtree, _) = | 1193 | let action: &'static _ = runnable.action(); |
1192 | get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); | 1194 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { |
1193 | let cfg_expr = parse_cfg(&subtree); | 1195 | let mut group = lsp_ext::CommandLinkGroup::default(); |
1194 | 1196 | ||
1195 | let mut min_features = vec![]; | 1197 | if snap.config.hover.run { |
1196 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | 1198 | let run_command = run_single_command(&r, action.run_title); |
1197 | assert_eq!(min_features, vec![SmolStr::new("baz")]); | 1199 | group.commands.push(to_command_link(run_command, r.label.clone())); |
1200 | } | ||
1198 | 1201 | ||
1199 | let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); | 1202 | if snap.config.hover.debug { |
1200 | let cfg_expr = parse_cfg(&subtree); | 1203 | let dbg_command = debug_single_command(&r); |
1204 | group.commands.push(to_command_link(dbg_command, r.label)); | ||
1205 | } | ||
1206 | |||
1207 | group | ||
1208 | }) | ||
1209 | } | ||
1210 | |||
1211 | fn prepare_hover_actions( | ||
1212 | snap: &GlobalStateSnapshot, | ||
1213 | file_id: FileId, | ||
1214 | actions: &[HoverAction], | ||
1215 | ) -> Vec<lsp_ext::CommandLinkGroup> { | ||
1216 | if snap.config.hover.none() || !snap.config.client_caps.hover_actions { | ||
1217 | return Vec::new(); | ||
1218 | } | ||
1201 | 1219 | ||
1202 | let mut min_features = vec![]; | 1220 | actions |
1203 | collect_minimal_features_needed(&cfg_expr, &mut min_features); | 1221 | .iter() |
1204 | assert!(min_features.is_empty()); | 1222 | .filter_map(|it| match it { |
1223 | HoverAction::Implementaion(position) => show_impl_command_link(snap, position), | ||
1224 | HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r.clone()), | ||
1225 | }) | ||
1226 | .collect() | ||
1227 | } | ||
1228 | |||
1229 | fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { | ||
1230 | match runnable.kind { | ||
1231 | RunnableKind::Bin => { | ||
1232 | // Do not suggest binary run on other target than binary | ||
1233 | match &cargo_spec { | ||
1234 | Some(spec) => spec.target_kind != TargetKind::Bin, | ||
1235 | None => true, | ||
1236 | } | ||
1237 | } | ||
1238 | _ => false, | ||
1205 | } | 1239 | } |
1206 | } | 1240 | } |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 2fbbb4e63..710df1fbd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -3,13 +3,16 @@ use ra_db::{FileId, FileRange}; | |||
3 | use ra_ide::{ | 3 | use ra_ide::{ |
4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, Severity, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, |
7 | SourceChange, SourceFileEdit, TextEdit, | 7 | ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
11 | 11 | ||
12 | use crate::{lsp_ext, semantic_tokens, world::WorldSnapshot, Result}; | 12 | use crate::{ |
13 | cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, lsp_ext, | ||
14 | semantic_tokens, Result, | ||
15 | }; | ||
13 | 16 | ||
14 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { | 17 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { |
15 | let line_col = line_index.line_col(offset); | 18 | let line_col = line_index.line_col(offset); |
@@ -382,41 +385,44 @@ pub(crate) fn folding_range( | |||
382 | } | 385 | } |
383 | } | 386 | } |
384 | 387 | ||
385 | pub(crate) fn url(world: &WorldSnapshot, file_id: FileId) -> Result<lsp_types::Url> { | 388 | pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> Result<lsp_types::Url> { |
386 | world.file_id_to_uri(file_id) | 389 | snap.file_id_to_uri(file_id) |
387 | } | 390 | } |
388 | 391 | ||
389 | pub(crate) fn versioned_text_document_identifier( | 392 | pub(crate) fn versioned_text_document_identifier( |
390 | world: &WorldSnapshot, | 393 | snap: &GlobalStateSnapshot, |
391 | file_id: FileId, | 394 | file_id: FileId, |
392 | version: Option<i64>, | 395 | version: Option<i64>, |
393 | ) -> Result<lsp_types::VersionedTextDocumentIdentifier> { | 396 | ) -> Result<lsp_types::VersionedTextDocumentIdentifier> { |
394 | let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(world, file_id)?, version }; | 397 | let res = lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id)?, version }; |
395 | Ok(res) | 398 | Ok(res) |
396 | } | 399 | } |
397 | 400 | ||
398 | pub(crate) fn location(world: &WorldSnapshot, frange: FileRange) -> Result<lsp_types::Location> { | 401 | pub(crate) fn location( |
399 | let url = url(world, frange.file_id)?; | 402 | snap: &GlobalStateSnapshot, |
400 | let line_index = world.analysis().file_line_index(frange.file_id)?; | 403 | frange: FileRange, |
404 | ) -> Result<lsp_types::Location> { | ||
405 | let url = url(snap, frange.file_id)?; | ||
406 | let line_index = snap.analysis().file_line_index(frange.file_id)?; | ||
401 | let range = range(&line_index, frange.range); | 407 | let range = range(&line_index, frange.range); |
402 | let loc = lsp_types::Location::new(url, range); | 408 | let loc = lsp_types::Location::new(url, range); |
403 | Ok(loc) | 409 | Ok(loc) |
404 | } | 410 | } |
405 | 411 | ||
406 | pub(crate) fn location_link( | 412 | pub(crate) fn location_link( |
407 | world: &WorldSnapshot, | 413 | snap: &GlobalStateSnapshot, |
408 | src: Option<FileRange>, | 414 | src: Option<FileRange>, |
409 | target: NavigationTarget, | 415 | target: NavigationTarget, |
410 | ) -> Result<lsp_types::LocationLink> { | 416 | ) -> Result<lsp_types::LocationLink> { |
411 | let origin_selection_range = match src { | 417 | let origin_selection_range = match src { |
412 | Some(src) => { | 418 | Some(src) => { |
413 | let line_index = world.analysis().file_line_index(src.file_id)?; | 419 | let line_index = snap.analysis().file_line_index(src.file_id)?; |
414 | let range = range(&line_index, src.range); | 420 | let range = range(&line_index, src.range); |
415 | Some(range) | 421 | Some(range) |
416 | } | 422 | } |
417 | None => None, | 423 | None => None, |
418 | }; | 424 | }; |
419 | let (target_uri, target_range, target_selection_range) = location_info(world, target)?; | 425 | let (target_uri, target_range, target_selection_range) = location_info(snap, target)?; |
420 | let res = lsp_types::LocationLink { | 426 | let res = lsp_types::LocationLink { |
421 | origin_selection_range, | 427 | origin_selection_range, |
422 | target_uri, | 428 | target_uri, |
@@ -427,12 +433,12 @@ pub(crate) fn location_link( | |||
427 | } | 433 | } |
428 | 434 | ||
429 | fn location_info( | 435 | fn location_info( |
430 | world: &WorldSnapshot, | 436 | snap: &GlobalStateSnapshot, |
431 | target: NavigationTarget, | 437 | target: NavigationTarget, |
432 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { | 438 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { |
433 | let line_index = world.analysis().file_line_index(target.file_id())?; | 439 | let line_index = snap.analysis().file_line_index(target.file_id())?; |
434 | 440 | ||
435 | let target_uri = url(world, target.file_id())?; | 441 | let target_uri = url(snap, target.file_id())?; |
436 | let target_range = range(&line_index, target.full_range()); | 442 | let target_range = range(&line_index, target.full_range()); |
437 | let target_selection_range = | 443 | let target_selection_range = |
438 | target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); | 444 | target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); |
@@ -440,14 +446,14 @@ fn location_info( | |||
440 | } | 446 | } |
441 | 447 | ||
442 | pub(crate) fn goto_definition_response( | 448 | pub(crate) fn goto_definition_response( |
443 | world: &WorldSnapshot, | 449 | snap: &GlobalStateSnapshot, |
444 | src: Option<FileRange>, | 450 | src: Option<FileRange>, |
445 | targets: Vec<NavigationTarget>, | 451 | targets: Vec<NavigationTarget>, |
446 | ) -> Result<lsp_types::GotoDefinitionResponse> { | 452 | ) -> Result<lsp_types::GotoDefinitionResponse> { |
447 | if world.config.client_caps.location_link { | 453 | if snap.config.client_caps.location_link { |
448 | let links = targets | 454 | let links = targets |
449 | .into_iter() | 455 | .into_iter() |
450 | .map(|nav| location_link(world, src, nav)) | 456 | .map(|nav| location_link(snap, src, nav)) |
451 | .collect::<Result<Vec<_>>>()?; | 457 | .collect::<Result<Vec<_>>>()?; |
452 | Ok(links.into()) | 458 | Ok(links.into()) |
453 | } else { | 459 | } else { |
@@ -455,7 +461,7 @@ pub(crate) fn goto_definition_response( | |||
455 | .into_iter() | 461 | .into_iter() |
456 | .map(|nav| { | 462 | .map(|nav| { |
457 | location( | 463 | location( |
458 | world, | 464 | snap, |
459 | FileRange { | 465 | FileRange { |
460 | file_id: nav.file_id(), | 466 | file_id: nav.file_id(), |
461 | range: nav.focus_range().unwrap_or(nav.range()), | 467 | range: nav.focus_range().unwrap_or(nav.range()), |
@@ -468,13 +474,13 @@ pub(crate) fn goto_definition_response( | |||
468 | } | 474 | } |
469 | 475 | ||
470 | pub(crate) fn snippet_text_document_edit( | 476 | pub(crate) fn snippet_text_document_edit( |
471 | world: &WorldSnapshot, | 477 | snap: &GlobalStateSnapshot, |
472 | is_snippet: bool, | 478 | is_snippet: bool, |
473 | source_file_edit: SourceFileEdit, | 479 | source_file_edit: SourceFileEdit, |
474 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { | 480 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { |
475 | let text_document = versioned_text_document_identifier(world, source_file_edit.file_id, None)?; | 481 | let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None)?; |
476 | let line_index = world.analysis().file_line_index(source_file_edit.file_id)?; | 482 | let line_index = snap.analysis().file_line_index(source_file_edit.file_id)?; |
477 | let line_endings = world.file_line_endings(source_file_edit.file_id); | 483 | let line_endings = snap.file_line_endings(source_file_edit.file_id); |
478 | let edits = source_file_edit | 484 | let edits = source_file_edit |
479 | .edit | 485 | .edit |
480 | .into_iter() | 486 | .into_iter() |
@@ -484,17 +490,17 @@ pub(crate) fn snippet_text_document_edit( | |||
484 | } | 490 | } |
485 | 491 | ||
486 | pub(crate) fn resource_op( | 492 | pub(crate) fn resource_op( |
487 | world: &WorldSnapshot, | 493 | snap: &GlobalStateSnapshot, |
488 | file_system_edit: FileSystemEdit, | 494 | file_system_edit: FileSystemEdit, |
489 | ) -> Result<lsp_types::ResourceOp> { | 495 | ) -> Result<lsp_types::ResourceOp> { |
490 | let res = match file_system_edit { | 496 | let res = match file_system_edit { |
491 | FileSystemEdit::CreateFile { source_root, path } => { | 497 | FileSystemEdit::CreateFile { source_root, path } => { |
492 | let uri = world.path_to_uri(source_root, &path)?; | 498 | let uri = snap.path_to_uri(source_root, &path)?; |
493 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None }) | 499 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None }) |
494 | } | 500 | } |
495 | FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => { | 501 | FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => { |
496 | let old_uri = world.file_id_to_uri(src)?; | 502 | let old_uri = snap.file_id_to_uri(src)?; |
497 | let new_uri = world.path_to_uri(dst_source_root, &dst_path)?; | 503 | let new_uri = snap.path_to_uri(dst_source_root, &dst_path)?; |
498 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None }) | 504 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None }) |
499 | } | 505 | } |
500 | }; | 506 | }; |
@@ -502,16 +508,16 @@ pub(crate) fn resource_op( | |||
502 | } | 508 | } |
503 | 509 | ||
504 | pub(crate) fn snippet_workspace_edit( | 510 | pub(crate) fn snippet_workspace_edit( |
505 | world: &WorldSnapshot, | 511 | snap: &GlobalStateSnapshot, |
506 | source_change: SourceChange, | 512 | source_change: SourceChange, |
507 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { | 513 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { |
508 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); | 514 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); |
509 | for op in source_change.file_system_edits { | 515 | for op in source_change.file_system_edits { |
510 | let op = resource_op(&world, op)?; | 516 | let op = resource_op(&snap, op)?; |
511 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); | 517 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); |
512 | } | 518 | } |
513 | for edit in source_change.source_file_edits { | 519 | for edit in source_change.source_file_edits { |
514 | let edit = snippet_text_document_edit(&world, source_change.is_snippet, edit)?; | 520 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; |
515 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); | 521 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); |
516 | } | 522 | } |
517 | let workspace_edit = | 523 | let workspace_edit = |
@@ -520,11 +526,11 @@ pub(crate) fn snippet_workspace_edit( | |||
520 | } | 526 | } |
521 | 527 | ||
522 | pub(crate) fn workspace_edit( | 528 | pub(crate) fn workspace_edit( |
523 | world: &WorldSnapshot, | 529 | snap: &GlobalStateSnapshot, |
524 | source_change: SourceChange, | 530 | source_change: SourceChange, |
525 | ) -> Result<lsp_types::WorkspaceEdit> { | 531 | ) -> Result<lsp_types::WorkspaceEdit> { |
526 | assert!(!source_change.is_snippet); | 532 | assert!(!source_change.is_snippet); |
527 | snippet_workspace_edit(world, source_change).map(|it| it.into()) | 533 | snippet_workspace_edit(snap, source_change).map(|it| it.into()) |
528 | } | 534 | } |
529 | 535 | ||
530 | impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { | 536 | impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { |
@@ -563,13 +569,13 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { | |||
563 | } | 569 | } |
564 | 570 | ||
565 | pub fn call_hierarchy_item( | 571 | pub fn call_hierarchy_item( |
566 | world: &WorldSnapshot, | 572 | snap: &GlobalStateSnapshot, |
567 | target: NavigationTarget, | 573 | target: NavigationTarget, |
568 | ) -> Result<lsp_types::CallHierarchyItem> { | 574 | ) -> Result<lsp_types::CallHierarchyItem> { |
569 | let name = target.name().to_string(); | 575 | let name = target.name().to_string(); |
570 | let detail = target.description().map(|it| it.to_string()); | 576 | let detail = target.description().map(|it| it.to_string()); |
571 | let kind = symbol_kind(target.kind()); | 577 | let kind = symbol_kind(target.kind()); |
572 | let (uri, range, selection_range) = location_info(world, target)?; | 578 | let (uri, range, selection_range) = location_info(snap, target)?; |
573 | Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) | 579 | Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) |
574 | } | 580 | } |
575 | 581 | ||
@@ -617,13 +623,56 @@ fn main() <fold>{ | |||
617 | } | 623 | } |
618 | } | 624 | } |
619 | 625 | ||
620 | pub(crate) fn code_action(world: &WorldSnapshot, assist: Assist) -> Result<lsp_ext::CodeAction> { | 626 | pub(crate) fn unresolved_code_action( |
627 | snap: &GlobalStateSnapshot, | ||
628 | assist: Assist, | ||
629 | index: usize, | ||
630 | ) -> Result<lsp_ext::CodeAction> { | ||
621 | let res = lsp_ext::CodeAction { | 631 | let res = lsp_ext::CodeAction { |
622 | title: assist.label, | 632 | title: assist.label, |
623 | group: if world.config.client_caps.code_action_group { assist.group_label } else { None }, | 633 | id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())), |
634 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | ||
624 | kind: Some(String::new()), | 635 | kind: Some(String::new()), |
625 | edit: Some(snippet_workspace_edit(world, assist.source_change)?), | 636 | edit: None, |
626 | command: None, | 637 | command: None, |
627 | }; | 638 | }; |
628 | Ok(res) | 639 | Ok(res) |
629 | } | 640 | } |
641 | |||
642 | pub(crate) fn resolved_code_action( | ||
643 | snap: &GlobalStateSnapshot, | ||
644 | assist: ResolvedAssist, | ||
645 | ) -> Result<lsp_ext::CodeAction> { | ||
646 | let change = assist.source_change; | ||
647 | unresolved_code_action(snap, assist.assist, 0).and_then(|it| { | ||
648 | Ok(lsp_ext::CodeAction { | ||
649 | id: None, | ||
650 | edit: Some(snippet_workspace_edit(snap, change)?), | ||
651 | ..it | ||
652 | }) | ||
653 | }) | ||
654 | } | ||
655 | |||
656 | pub(crate) fn runnable( | ||
657 | snap: &GlobalStateSnapshot, | ||
658 | file_id: FileId, | ||
659 | runnable: Runnable, | ||
660 | ) -> Result<lsp_ext::Runnable> { | ||
661 | let spec = CargoTargetSpec::for_file(snap, file_id)?; | ||
662 | let target = spec.as_ref().map(|s| s.target.clone()); | ||
663 | let (cargo_args, executable_args) = | ||
664 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; | ||
665 | let label = runnable.label(target); | ||
666 | let location = location_link(snap, None, runnable.nav)?; | ||
667 | |||
668 | Ok(lsp_ext::Runnable { | ||
669 | label, | ||
670 | location: Some(location), | ||
671 | kind: lsp_ext::RunnableKind::Cargo, | ||
672 | args: lsp_ext::CargoRunnable { | ||
673 | workspace_root: snap.workspace_root_for(file_id).map(|root| root.to_owned()), | ||
674 | cargo_args, | ||
675 | executable_args, | ||
676 | }, | ||
677 | }) | ||
678 | } | ||
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 405ddb362..0e2a83c6a 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -4,9 +4,7 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; | |||
4 | 4 | ||
5 | use lsp_types::{ | 5 | use lsp_types::{ |
6 | notification::DidOpenTextDocument, | 6 | notification::DidOpenTextDocument, |
7 | request::{ | 7 | request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, |
8 | CodeActionRequest, Completion, Formatting, GotoDefinition, GotoTypeDefinition, HoverRequest, | ||
9 | }, | ||
10 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, | 8 | CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams, |
11 | DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams, | 9 | DocumentFormattingParams, FormattingOptions, GotoDefinitionParams, HoverParams, |
12 | PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, | 10 | PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, |
@@ -59,52 +57,6 @@ use std::collections::Spam; | |||
59 | } | 57 | } |
60 | 58 | ||
61 | #[test] | 59 | #[test] |
62 | fn test_runnables_no_project() { | ||
63 | if skip_slow_tests() { | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | let server = project( | ||
68 | r" | ||
69 | //- lib.rs | ||
70 | #[test] | ||
71 | fn foo() { | ||
72 | } | ||
73 | ", | ||
74 | ); | ||
75 | server.wait_until_workspace_is_loaded(); | ||
76 | server.request::<Runnables>( | ||
77 | RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, | ||
78 | json!([ | ||
79 | { | ||
80 | "args": [ "test" ], | ||
81 | "extraArgs": [ "foo", "--nocapture" ], | ||
82 | "bin": "cargo", | ||
83 | "env": { "RUST_BACKTRACE": "short" }, | ||
84 | "cwd": null, | ||
85 | "label": "test foo", | ||
86 | "range": { | ||
87 | "end": { "character": 1, "line": 2 }, | ||
88 | "start": { "character": 0, "line": 0 } | ||
89 | } | ||
90 | }, | ||
91 | { | ||
92 | "args": ["check", "--workspace"], | ||
93 | "extraArgs": [], | ||
94 | "bin": "cargo", | ||
95 | "env": {}, | ||
96 | "cwd": null, | ||
97 | "label": "cargo check --workspace", | ||
98 | "range": { | ||
99 | "end": { "character": 0, "line": 0 }, | ||
100 | "start": { "character": 0, "line": 0 } | ||
101 | } | ||
102 | } | ||
103 | ]), | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn test_runnables_project() { | 60 | fn test_runnables_project() { |
109 | if skip_slow_tests() { | 61 | if skip_slow_tests() { |
110 | return; | 62 | return; |
@@ -138,42 +90,44 @@ fn main() {} | |||
138 | server.request::<Runnables>( | 90 | server.request::<Runnables>( |
139 | RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, | 91 | RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, |
140 | json!([ | 92 | json!([ |
141 | { | 93 | { |
142 | "args": [ "test", "--package", "foo", "--test", "spam" ], | 94 | "args": { |
143 | "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], | 95 | "cargoArgs": ["test", "--package", "foo", "--test", "spam"], |
144 | "bin": "cargo", | 96 | "executableArgs": ["test_eggs", "--exact", "--nocapture"], |
145 | "env": { "RUST_BACKTRACE": "short" }, | 97 | "workspaceRoot": server.path().join("foo") |
146 | "label": "test test_eggs", | 98 | }, |
147 | "range": { | 99 | "kind": "cargo", |
100 | "label": "test test_eggs", | ||
101 | "location": { | ||
102 | "targetRange": { | ||
148 | "end": { "character": 17, "line": 1 }, | 103 | "end": { "character": 17, "line": 1 }, |
149 | "start": { "character": 0, "line": 0 } | 104 | "start": { "character": 0, "line": 0 } |
150 | }, | 105 | }, |
151 | "cwd": server.path().join("foo") | 106 | "targetSelectionRange": { |
152 | }, | 107 | "end": { "character": 12, "line": 1 }, |
153 | { | 108 | "start": { "character": 3, "line": 1 } |
154 | "args": [ "check", "--package", "foo" ], | ||
155 | "extraArgs": [], | ||
156 | "bin": "cargo", | ||
157 | "env": {}, | ||
158 | "label": "cargo check -p foo", | ||
159 | "range": { | ||
160 | "end": { "character": 0, "line": 0 }, | ||
161 | "start": { "character": 0, "line": 0 } | ||
162 | }, | 109 | }, |
163 | "cwd": server.path().join("foo") | 110 | "targetUri": "file:///[..]/tests/spam.rs" |
164 | }, | ||
165 | { | ||
166 | "args": [ "test", "--package", "foo" ], | ||
167 | "extraArgs": [], | ||
168 | "bin": "cargo", | ||
169 | "env": {}, | ||
170 | "label": "cargo test -p foo", | ||
171 | "range": { | ||
172 | "end": { "character": 0, "line": 0 }, | ||
173 | "start": { "character": 0, "line": 0 } | ||
174 | }, | ||
175 | "cwd": server.path().join("foo") | ||
176 | } | 111 | } |
112 | }, | ||
113 | { | ||
114 | "args": { | ||
115 | "cargoArgs": ["check", "--package", "foo"], | ||
116 | "executableArgs": [], | ||
117 | "workspaceRoot": server.path().join("foo") | ||
118 | }, | ||
119 | "kind": "cargo", | ||
120 | "label": "cargo check -p foo" | ||
121 | }, | ||
122 | { | ||
123 | "args": { | ||
124 | "cargoArgs": ["test", "--package", "foo"], | ||
125 | "executableArgs": [], | ||
126 | "workspaceRoot": server.path().join("foo") | ||
127 | }, | ||
128 | "kind": "cargo", | ||
129 | "label": "cargo test -p foo" | ||
130 | } | ||
177 | ]), | 131 | ]), |
178 | ); | 132 | ); |
179 | } | 133 | } |
@@ -342,6 +296,7 @@ fn main() {} | |||
342 | } | 296 | } |
343 | ] | 297 | ] |
344 | }, | 298 | }, |
299 | "kind": "quickfix", | ||
345 | "title": "Create module" | 300 | "title": "Create module" |
346 | }]), | 301 | }]), |
347 | ); | 302 | ); |
@@ -374,8 +329,7 @@ fn test_missing_module_code_action_in_json_project() { | |||
374 | "root_module": path.join("src/lib.rs"), | 329 | "root_module": path.join("src/lib.rs"), |
375 | "deps": [], | 330 | "deps": [], |
376 | "edition": "2015", | 331 | "edition": "2015", |
377 | "atom_cfgs": [], | 332 | "cfg": [ "cfg_atom_1", "feature=cfg_1"], |
378 | "key_value_cfgs": {} | ||
379 | } ] | 333 | } ] |
380 | }); | 334 | }); |
381 | 335 | ||
@@ -413,6 +367,7 @@ fn main() {{}} | |||
413 | } | 367 | } |
414 | ] | 368 | ] |
415 | }, | 369 | }, |
370 | "kind": "quickfix", | ||
416 | "title": "Create module" | 371 | "title": "Create module" |
417 | }]), | 372 | }]), |
418 | ); | 373 | ); |
@@ -550,6 +505,10 @@ fn main() { | |||
550 | println!("cargo:rerun-if-changed=build.rs"); | 505 | println!("cargo:rerun-if-changed=build.rs"); |
551 | } | 506 | } |
552 | //- src/main.rs | 507 | //- src/main.rs |
508 | #[rustc_builtin_macro] macro_rules! include {} | ||
509 | #[rustc_builtin_macro] macro_rules! concat {} | ||
510 | #[rustc_builtin_macro] macro_rules! env {} | ||
511 | |||
553 | include!(concat!(env!("OUT_DIR"), "/hello.rs")); | 512 | include!(concat!(env!("OUT_DIR"), "/hello.rs")); |
554 | 513 | ||
555 | #[cfg(atom_cfg)] | 514 | #[cfg(atom_cfg)] |
@@ -564,10 +523,8 @@ struct B; | |||
564 | fn main() { | 523 | fn main() { |
565 | let va = A; | 524 | let va = A; |
566 | let vb = B; | 525 | let vb = B; |
567 | message(); | 526 | let should_be_str = message(); |
568 | } | 527 | } |
569 | |||
570 | fn main() { message(); } | ||
571 | "###, | 528 | "###, |
572 | ) | 529 | ) |
573 | .with_config(|config| { | 530 | .with_config(|config| { |
@@ -575,54 +532,35 @@ fn main() { message(); } | |||
575 | }) | 532 | }) |
576 | .server(); | 533 | .server(); |
577 | server.wait_until_workspace_is_loaded(); | 534 | server.wait_until_workspace_is_loaded(); |
578 | let res = server.send_request::<GotoDefinition>(GotoDefinitionParams { | 535 | let res = server.send_request::<HoverRequest>(HoverParams { |
579 | text_document_position_params: TextDocumentPositionParams::new( | 536 | text_document_position_params: TextDocumentPositionParams::new( |
580 | server.doc_id("src/main.rs"), | 537 | server.doc_id("src/main.rs"), |
581 | Position::new(14, 8), | 538 | Position::new(18, 10), |
582 | ), | 539 | ), |
583 | work_done_progress_params: Default::default(), | 540 | work_done_progress_params: Default::default(), |
584 | partial_result_params: Default::default(), | ||
585 | }); | 541 | }); |
586 | assert!(format!("{}", res).contains("hello.rs")); | 542 | assert!(res.to_string().contains("&str")); |
587 | server.request::<GotoTypeDefinition>( | 543 | server.request::<GotoTypeDefinition>( |
588 | GotoDefinitionParams { | 544 | GotoDefinitionParams { |
589 | text_document_position_params: TextDocumentPositionParams::new( | 545 | text_document_position_params: TextDocumentPositionParams::new( |
590 | server.doc_id("src/main.rs"), | 546 | server.doc_id("src/main.rs"), |
591 | Position::new(12, 9), | 547 | Position::new(16, 9), |
592 | ), | 548 | ), |
593 | work_done_progress_params: Default::default(), | 549 | work_done_progress_params: Default::default(), |
594 | partial_result_params: Default::default(), | 550 | partial_result_params: Default::default(), |
595 | }, | 551 | }, |
596 | json!([{ | 552 | json!([{ |
597 | "originSelectionRange": { | 553 | "originSelectionRange": { |
598 | "end": { | 554 | "end": { "character": 10, "line": 16 }, |
599 | "character": 10, | 555 | "start": { "character": 8, "line": 16 } |
600 | "line": 12 | ||
601 | }, | ||
602 | "start": { | ||
603 | "character": 8, | ||
604 | "line": 12 | ||
605 | } | ||
606 | }, | 556 | }, |
607 | "targetRange": { | 557 | "targetRange": { |
608 | "end": { | 558 | "end": { "character": 9, "line": 7 }, |
609 | "character": 9, | 559 | "start": { "character": 0, "line": 6 } |
610 | "line": 3 | ||
611 | }, | ||
612 | "start": { | ||
613 | "character": 0, | ||
614 | "line": 2 | ||
615 | } | ||
616 | }, | 560 | }, |
617 | "targetSelectionRange": { | 561 | "targetSelectionRange": { |
618 | "end": { | 562 | "end": { "character": 8, "line": 7 }, |
619 | "character": 8, | 563 | "start": { "character": 7, "line": 7 } |
620 | "line": 3 | ||
621 | }, | ||
622 | "start": { | ||
623 | "character": 7, | ||
624 | "line": 3 | ||
625 | } | ||
626 | }, | 564 | }, |
627 | "targetUri": "file:///[..]src/main.rs" | 565 | "targetUri": "file:///[..]src/main.rs" |
628 | }]), | 566 | }]), |
@@ -631,41 +569,23 @@ fn main() { message(); } | |||
631 | GotoDefinitionParams { | 569 | GotoDefinitionParams { |
632 | text_document_position_params: TextDocumentPositionParams::new( | 570 | text_document_position_params: TextDocumentPositionParams::new( |
633 | server.doc_id("src/main.rs"), | 571 | server.doc_id("src/main.rs"), |
634 | Position::new(13, 9), | 572 | Position::new(17, 9), |
635 | ), | 573 | ), |
636 | work_done_progress_params: Default::default(), | 574 | work_done_progress_params: Default::default(), |
637 | partial_result_params: Default::default(), | 575 | partial_result_params: Default::default(), |
638 | }, | 576 | }, |
639 | json!([{ | 577 | json!([{ |
640 | "originSelectionRange": { | 578 | "originSelectionRange": { |
641 | "end": { | 579 | "end": { "character": 10, "line": 17 }, |
642 | "character": 10, | 580 | "start": { "character": 8, "line": 17 } |
643 | "line": 13 | ||
644 | }, | ||
645 | "start": { | ||
646 | "character": 8, | ||
647 | "line":13 | ||
648 | } | ||
649 | }, | 581 | }, |
650 | "targetRange": { | 582 | "targetRange": { |
651 | "end": { | 583 | "end": { "character": 9, "line": 11 }, |
652 | "character": 9, | 584 | "start": { "character": 0, "line":10 } |
653 | "line": 7 | ||
654 | }, | ||
655 | "start": { | ||
656 | "character": 0, | ||
657 | "line":6 | ||
658 | } | ||
659 | }, | 585 | }, |
660 | "targetSelectionRange": { | 586 | "targetSelectionRange": { |
661 | "end": { | 587 | "end": { "character": 8, "line": 11 }, |
662 | "character": 8, | 588 | "start": { "character": 7, "line": 11 } |
663 | "line": 7 | ||
664 | }, | ||
665 | "start": { | ||
666 | "character": 7, | ||
667 | "line": 7 | ||
668 | } | ||
669 | }, | 589 | }, |
670 | "targetUri": "file:///[..]src/main.rs" | 590 | "targetUri": "file:///[..]src/main.rs" |
671 | }]), | 591 | }]), |
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 66a6f4d54..30d03b622 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -19,8 +19,9 @@ use serde_json::{to_string_pretty, Value}; | |||
19 | use tempfile::TempDir; | 19 | use tempfile::TempDir; |
20 | use test_utils::{find_mismatch, parse_fixture}; | 20 | use test_utils::{find_mismatch, parse_fixture}; |
21 | 21 | ||
22 | use ra_project_model::ProjectManifest; | ||
22 | use rust_analyzer::{ | 23 | use rust_analyzer::{ |
23 | config::{ClientCapsConfig, Config}, | 24 | config::{ClientCapsConfig, Config, LinkedProject}, |
24 | main_loop, | 25 | main_loop, |
25 | }; | 26 | }; |
26 | 27 | ||
@@ -42,7 +43,7 @@ impl<'a> Project<'a> { | |||
42 | self | 43 | self |
43 | } | 44 | } |
44 | 45 | ||
45 | pub fn root(mut self, path: &str) -> Project<'a> { | 46 | pub(crate) fn root(mut self, path: &str) -> Project<'a> { |
46 | self.roots.push(path.into()); | 47 | self.roots.push(path.into()); |
47 | self | 48 | self |
48 | } | 49 | } |
@@ -74,7 +75,16 @@ impl<'a> Project<'a> { | |||
74 | paths.push((path, entry.text)); | 75 | paths.push((path, entry.text)); |
75 | } | 76 | } |
76 | 77 | ||
77 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); | 78 | let mut roots = |
79 | self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::<Vec<_>>(); | ||
80 | if roots.is_empty() { | ||
81 | roots.push(tmp_dir.path().to_path_buf()); | ||
82 | } | ||
83 | let linked_projects = roots | ||
84 | .into_iter() | ||
85 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) | ||
86 | .map(LinkedProject::from) | ||
87 | .collect::<Vec<_>>(); | ||
78 | 88 | ||
79 | let mut config = Config { | 89 | let mut config = Config { |
80 | client_caps: ClientCapsConfig { | 90 | client_caps: ClientCapsConfig { |
@@ -84,6 +94,7 @@ impl<'a> Project<'a> { | |||
84 | ..Default::default() | 94 | ..Default::default() |
85 | }, | 95 | }, |
86 | with_sysroot: self.with_sysroot, | 96 | with_sysroot: self.with_sysroot, |
97 | linked_projects, | ||
87 | ..Config::default() | 98 | ..Config::default() |
88 | }; | 99 | }; |
89 | 100 | ||
@@ -91,7 +102,7 @@ impl<'a> Project<'a> { | |||
91 | f(&mut config) | 102 | f(&mut config) |
92 | } | 103 | } |
93 | 104 | ||
94 | Server::new(tmp_dir, config, roots, paths) | 105 | Server::new(tmp_dir, config, paths) |
95 | } | 106 | } |
96 | } | 107 | } |
97 | 108 | ||
@@ -109,20 +120,12 @@ pub struct Server { | |||
109 | } | 120 | } |
110 | 121 | ||
111 | impl Server { | 122 | impl Server { |
112 | fn new( | 123 | fn new(dir: TempDir, config: Config, files: Vec<(PathBuf, String)>) -> Server { |
113 | dir: TempDir, | ||
114 | config: Config, | ||
115 | roots: Vec<PathBuf>, | ||
116 | files: Vec<(PathBuf, String)>, | ||
117 | ) -> Server { | ||
118 | let path = dir.path().to_path_buf(); | ||
119 | |||
120 | let roots = if roots.is_empty() { vec![path] } else { roots }; | ||
121 | let (connection, client) = Connection::memory(); | 124 | let (connection, client) = Connection::memory(); |
122 | 125 | ||
123 | let _thread = jod_thread::Builder::new() | 126 | let _thread = jod_thread::Builder::new() |
124 | .name("test server".to_string()) | 127 | .name("test server".to_string()) |
125 | .spawn(move || main_loop(roots, config, connection).unwrap()) | 128 | .spawn(move || main_loop(config, connection).unwrap()) |
126 | .expect("failed to spawn a thread"); | 129 | .expect("failed to spawn a thread"); |
127 | 130 | ||
128 | let res = | 131 | let res = |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 71a57fba2..c0356344c 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -124,3 +124,8 @@ pub fn replace(buf: &mut String, from: char, to: &str) { | |||
124 | // FIXME: do this in place. | 124 | // FIXME: do this in place. |
125 | *buf = buf.replace(from, to) | 125 | *buf = buf.replace(from, to) |
126 | } | 126 | } |
127 | |||
128 | pub fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
129 | let idx = haystack.find(delim)?; | ||
130 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
131 | } | ||
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 4d185b01c..8840bf36a 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml | |||
@@ -14,4 +14,5 @@ serde_json = "1.0.48" | |||
14 | relative-path = "1.0.0" | 14 | relative-path = "1.0.0" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | 16 | ||
17 | ra_cfg = { path = "../ra_cfg" } \ No newline at end of file | 17 | ra_cfg = { path = "../ra_cfg" } |
18 | stdx = { path = "../stdx" } \ No newline at end of file | ||
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 1bd97215c..2141bfc20 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -15,6 +15,7 @@ use std::{ | |||
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub use ra_cfg::CfgOptions; | 17 | pub use ra_cfg::CfgOptions; |
18 | use stdx::split1; | ||
18 | 19 | ||
19 | pub use relative_path::{RelativePath, RelativePathBuf}; | 20 | pub use relative_path::{RelativePath, RelativePathBuf}; |
20 | pub use rustc_hash::FxHashMap; | 21 | pub use rustc_hash::FxHashMap; |
@@ -332,11 +333,6 @@ fn parse_meta(meta: &str) -> FixtureMeta { | |||
332 | FixtureMeta::File(FileMeta { path, crate_name: krate, deps, edition, cfg, env }) | 333 | FixtureMeta::File(FileMeta { path, crate_name: krate, deps, edition, cfg, env }) |
333 | } | 334 | } |
334 | 335 | ||
335 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
336 | let idx = haystack.find(delim)?; | ||
337 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
338 | } | ||
339 | |||
340 | /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. | 336 | /// Adjusts the indentation of the first line to the minimum indentation of the rest of the lines. |
341 | /// This allows fixtures to start off in a different indentation, e.g. to align the first line with | 337 | /// This allows fixtures to start off in a different indentation, e.g. to align the first line with |
342 | /// the other lines visually: | 338 | /// the other lines visually: |