diff options
-rw-r--r-- | crates/ra_assists/src/assist_context.rs | 60 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | 326 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/tests/generated.rs | 15 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 27 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 21 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 12 |
7 files changed, 423 insertions, 40 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 5b1a4680b..1925db8b2 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | assist_config::{AssistConfig, SnippetCap}, | 19 | assist_config::{AssistConfig, SnippetCap}, |
20 | Assist, AssistId, GroupLabel, ResolvedAssist, | 20 | Assist, AssistId, GroupLabel, ResolvedAssist, |
21 | }; | 21 | }; |
22 | use rustc_hash::FxHashMap; | ||
22 | 23 | ||
23 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 24 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
24 | /// | 25 | /// |
@@ -138,6 +139,16 @@ impl Assists { | |||
138 | let label = Assist::new(id, label.into(), None, target); | 139 | let label = Assist::new(id, label.into(), None, target); |
139 | self.add_impl(label, f) | 140 | self.add_impl(label, f) |
140 | } | 141 | } |
142 | pub(crate) fn add_in_multiple_files( | ||
143 | &mut self, | ||
144 | id: AssistId, | ||
145 | label: impl Into<String>, | ||
146 | target: TextRange, | ||
147 | f: impl FnOnce(&mut AssistDirector), | ||
148 | ) -> Option<()> { | ||
149 | let label = Assist::new(id, label.into(), None, target); | ||
150 | self.add_impl_multiple_files(label, f) | ||
151 | } | ||
141 | pub(crate) fn add_group( | 152 | pub(crate) fn add_group( |
142 | &mut self, | 153 | &mut self, |
143 | group: &GroupLabel, | 154 | group: &GroupLabel, |
@@ -162,6 +173,31 @@ impl Assists { | |||
162 | Some(()) | 173 | Some(()) |
163 | } | 174 | } |
164 | 175 | ||
176 | fn add_impl_multiple_files( | ||
177 | &mut self, | ||
178 | label: Assist, | ||
179 | f: impl FnOnce(&mut AssistDirector), | ||
180 | ) -> Option<()> { | ||
181 | if !self.resolve { | ||
182 | self.buf.push((label, None)); | ||
183 | return None; | ||
184 | } | ||
185 | let mut director = AssistDirector::default(); | ||
186 | f(&mut director); | ||
187 | let changes = director.finish(); | ||
188 | let file_edits: Vec<SourceFileEdit> = | ||
189 | changes.into_iter().map(|mut change| change.source_file_edits.pop().unwrap()).collect(); | ||
190 | |||
191 | let source_change = SourceChange { | ||
192 | source_file_edits: file_edits, | ||
193 | file_system_edits: vec![], | ||
194 | is_snippet: false, | ||
195 | }; | ||
196 | |||
197 | self.buf.push((label, Some(source_change))); | ||
198 | Some(()) | ||
199 | } | ||
200 | |||
165 | fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> { | 201 | fn finish(mut self) -> Vec<(Assist, Option<SourceChange>)> { |
166 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); | 202 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); |
167 | self.buf | 203 | self.buf |
@@ -255,3 +291,27 @@ impl AssistBuilder { | |||
255 | res | 291 | res |
256 | } | 292 | } |
257 | } | 293 | } |
294 | |||
295 | pub(crate) struct AssistDirector { | ||
296 | builders: FxHashMap<FileId, AssistBuilder>, | ||
297 | } | ||
298 | |||
299 | impl AssistDirector { | ||
300 | pub(crate) fn perform(&mut self, file_id: FileId, f: impl FnOnce(&mut AssistBuilder)) { | ||
301 | let mut builder = self.builders.entry(file_id).or_insert(AssistBuilder::new(file_id)); | ||
302 | f(&mut builder); | ||
303 | } | ||
304 | |||
305 | fn finish(self) -> Vec<SourceChange> { | ||
306 | self.builders | ||
307 | .into_iter() | ||
308 | .map(|(_, builder)| builder.finish()) | ||
309 | .collect::<Vec<SourceChange>>() | ||
310 | } | ||
311 | } | ||
312 | |||
313 | impl Default for AssistDirector { | ||
314 | fn default() -> Self { | ||
315 | AssistDirector { builders: FxHashMap::default() } | ||
316 | } | ||
317 | } | ||
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..2c455a1fd --- /dev/null +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -0,0 +1,326 @@ | |||
1 | use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; | ||
2 | use ra_syntax::{ | ||
3 | algo::find_node_at_offset, | ||
4 | ast::{self, AstNode, NameOwner}, | ||
5 | SourceFile, SyntaxNode, TextRange, TextSize, | ||
6 | }; | ||
7 | |||
8 | use crate::{ | ||
9 | assist_context::{AssistBuilder, AssistDirector}, | ||
10 | utils::insert_use_statement, | ||
11 | AssistContext, AssistId, Assists, | ||
12 | }; | ||
13 | use ast::{ArgListOwner, VisibilityOwner}; | ||
14 | use hir::{EnumVariant, Module, ModuleDef, Name}; | ||
15 | use ra_db::FileId; | ||
16 | use ra_fmt::leading_indent; | ||
17 | use rustc_hash::FxHashSet; | ||
18 | |||
19 | // Assist: extract_struct_from_enum_variant | ||
20 | // | ||
21 | // Extracts a struct from enum variant. | ||
22 | // | ||
23 | // ``` | ||
24 | // enum A { <|>One(u32, u32) } | ||
25 | // ``` | ||
26 | // -> | ||
27 | // ``` | ||
28 | // struct One(pub u32, pub u32); | ||
29 | // | ||
30 | // enum A { One(One) } | ||
31 | // ``` | ||
32 | pub(crate) fn extract_struct_from_enum_variant( | ||
33 | acc: &mut Assists, | ||
34 | ctx: &AssistContext, | ||
35 | ) -> Option<()> { | ||
36 | let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; | ||
37 | let field_list = match variant.kind() { | ||
38 | ast::StructKind::Tuple(field_list) => field_list, | ||
39 | _ => return None, | ||
40 | }; | ||
41 | let variant_name = variant.name()?.to_string(); | ||
42 | let variant_hir = ctx.sema.to_def(&variant)?; | ||
43 | if existing_struct_def(ctx.db, &variant_name, &variant_hir) { | ||
44 | return None; | ||
45 | } | ||
46 | let enum_ast = variant.parent_enum(); | ||
47 | let visibility = enum_ast.visibility(); | ||
48 | let enum_hir = ctx.sema.to_def(&enum_ast)?; | ||
49 | let variant_hir_name = variant_hir.name(ctx.db); | ||
50 | let enum_module_def = ModuleDef::from(enum_hir); | ||
51 | let current_module = enum_hir.module(ctx.db); | ||
52 | let target = variant.syntax().text_range(); | ||
53 | acc.add_in_multiple_files( | ||
54 | AssistId("extract_struct_from_enum_variant"), | ||
55 | "Extract struct from enum variant", | ||
56 | target, | ||
57 | |edit| { | ||
58 | let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); | ||
59 | let res = definition.find_usages(&ctx.db, None); | ||
60 | let start_offset = variant.parent_enum().syntax().text_range().start(); | ||
61 | let mut visited_modules_set = FxHashSet::default(); | ||
62 | visited_modules_set.insert(current_module); | ||
63 | for reference in res { | ||
64 | let source_file = ctx.sema.parse(reference.file_range.file_id); | ||
65 | update_reference( | ||
66 | ctx, | ||
67 | edit, | ||
68 | reference, | ||
69 | &source_file, | ||
70 | &enum_module_def, | ||
71 | &variant_hir_name, | ||
72 | &mut visited_modules_set, | ||
73 | ); | ||
74 | } | ||
75 | extract_struct_def( | ||
76 | edit, | ||
77 | enum_ast.syntax(), | ||
78 | &variant_name, | ||
79 | &field_list.to_string(), | ||
80 | start_offset, | ||
81 | ctx.frange.file_id, | ||
82 | &visibility, | ||
83 | ); | ||
84 | let list_range = field_list.syntax().text_range(); | ||
85 | update_variant(edit, &variant_name, ctx.frange.file_id, list_range); | ||
86 | }, | ||
87 | ) | ||
88 | } | ||
89 | |||
90 | fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool { | ||
91 | variant | ||
92 | .parent_enum(db) | ||
93 | .module(db) | ||
94 | .scope(db, None) | ||
95 | .into_iter() | ||
96 | .any(|(name, _)| name.to_string() == variant_name.to_string()) | ||
97 | } | ||
98 | |||
99 | fn insert_import( | ||
100 | ctx: &AssistContext, | ||
101 | builder: &mut AssistBuilder, | ||
102 | path: &ast::PathExpr, | ||
103 | module: &Module, | ||
104 | enum_module_def: &ModuleDef, | ||
105 | variant_hir_name: &Name, | ||
106 | ) -> Option<()> { | ||
107 | let db = ctx.db; | ||
108 | let mod_path = module.find_use_path(db, enum_module_def.clone()); | ||
109 | if let Some(mut mod_path) = mod_path { | ||
110 | mod_path.segments.pop(); | ||
111 | mod_path.segments.push(variant_hir_name.clone()); | ||
112 | insert_use_statement(path.syntax(), &mod_path, ctx, builder.text_edit_builder()); | ||
113 | } | ||
114 | Some(()) | ||
115 | } | ||
116 | |||
117 | fn extract_struct_def( | ||
118 | edit: &mut AssistDirector, | ||
119 | enum_ast: &SyntaxNode, | ||
120 | variant_name: &str, | ||
121 | variant_list: &str, | ||
122 | start_offset: TextSize, | ||
123 | file_id: FileId, | ||
124 | visibility: &Option<ast::Visibility>, | ||
125 | ) -> Option<()> { | ||
126 | let visibility_string = if let Some(visibility) = visibility { | ||
127 | format!("{} ", visibility.to_string()) | ||
128 | } else { | ||
129 | "".to_string() | ||
130 | }; | ||
131 | let indent = if let Some(indent) = leading_indent(enum_ast) { | ||
132 | indent.to_string() | ||
133 | } else { | ||
134 | "".to_string() | ||
135 | }; | ||
136 | let struct_def = format!( | ||
137 | r#"{}struct {}{}; | ||
138 | |||
139 | {}"#, | ||
140 | visibility_string, | ||
141 | variant_name, | ||
142 | list_with_visibility(variant_list), | ||
143 | indent | ||
144 | ); | ||
145 | edit.perform(file_id, |builder| { | ||
146 | builder.insert(start_offset, struct_def); | ||
147 | }); | ||
148 | Some(()) | ||
149 | } | ||
150 | |||
151 | fn update_variant( | ||
152 | edit: &mut AssistDirector, | ||
153 | variant_name: &str, | ||
154 | file_id: FileId, | ||
155 | list_range: TextRange, | ||
156 | ) -> Option<()> { | ||
157 | let inside_variant_range = TextRange::new( | ||
158 | list_range.start().checked_add(TextSize::from(1))?, | ||
159 | list_range.end().checked_sub(TextSize::from(1))?, | ||
160 | ); | ||
161 | edit.perform(file_id, |builder| { | ||
162 | builder.replace(inside_variant_range, variant_name); | ||
163 | }); | ||
164 | Some(()) | ||
165 | } | ||
166 | |||
167 | fn update_reference( | ||
168 | ctx: &AssistContext, | ||
169 | edit: &mut AssistDirector, | ||
170 | reference: Reference, | ||
171 | source_file: &SourceFile, | ||
172 | enum_module_def: &ModuleDef, | ||
173 | variant_hir_name: &Name, | ||
174 | visited_modules_set: &mut FxHashSet<Module>, | ||
175 | ) -> Option<()> { | ||
176 | let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>( | ||
177 | source_file.syntax(), | ||
178 | reference.file_range.range.start(), | ||
179 | )?; | ||
180 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | ||
181 | let list = call.arg_list()?; | ||
182 | let segment = path_expr.path()?.segment()?; | ||
183 | let module = ctx.sema.scope(&path_expr.syntax()).module()?; | ||
184 | let list_range = list.syntax().text_range(); | ||
185 | let inside_list_range = TextRange::new( | ||
186 | list_range.start().checked_add(TextSize::from(1))?, | ||
187 | list_range.end().checked_sub(TextSize::from(1))?, | ||
188 | ); | ||
189 | edit.perform(reference.file_range.file_id, |builder| { | ||
190 | if !visited_modules_set.contains(&module) { | ||
191 | if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name) | ||
192 | .is_some() | ||
193 | { | ||
194 | visited_modules_set.insert(module); | ||
195 | } | ||
196 | } | ||
197 | builder.replace(inside_list_range, format!("{}{}", segment, list)); | ||
198 | }); | ||
199 | Some(()) | ||
200 | } | ||
201 | |||
202 | fn list_with_visibility(list: &str) -> String { | ||
203 | list.split(',') | ||
204 | .map(|part| { | ||
205 | let index = if part.chars().next().unwrap() == '(' { 1usize } else { 0 }; | ||
206 | let mut mod_part = part.trim().to_string(); | ||
207 | mod_part.insert_str(index, "pub "); | ||
208 | mod_part | ||
209 | }) | ||
210 | .collect::<Vec<String>>() | ||
211 | .join(", ") | ||
212 | } | ||
213 | |||
214 | #[cfg(test)] | ||
215 | mod tests { | ||
216 | |||
217 | use crate::{ | ||
218 | tests::{check_assist, check_assist_not_applicable}, | ||
219 | utils::FamousDefs, | ||
220 | }; | ||
221 | |||
222 | use super::*; | ||
223 | |||
224 | #[test] | ||
225 | fn test_extract_struct_several_fields() { | ||
226 | check_assist( | ||
227 | extract_struct_from_enum_variant, | ||
228 | "enum A { <|>One(u32, u32) }", | ||
229 | r#"struct One(pub u32, pub u32); | ||
230 | |||
231 | enum A { One(One) }"#, | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn test_extract_struct_one_field() { | ||
237 | check_assist( | ||
238 | extract_struct_from_enum_variant, | ||
239 | "enum A { <|>One(u32) }", | ||
240 | r#"struct One(pub u32); | ||
241 | |||
242 | enum A { One(One) }"#, | ||
243 | ); | ||
244 | } | ||
245 | |||
246 | #[test] | ||
247 | fn test_extract_struct_pub_visibility() { | ||
248 | check_assist( | ||
249 | extract_struct_from_enum_variant, | ||
250 | "pub enum A { <|>One(u32, u32) }", | ||
251 | r#"pub struct One(pub u32, pub u32); | ||
252 | |||
253 | pub enum A { One(One) }"#, | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn test_extract_struct_with_complex_imports() { | ||
259 | check_assist( | ||
260 | extract_struct_from_enum_variant, | ||
261 | r#"mod my_mod { | ||
262 | fn another_fn() { | ||
263 | let m = my_other_mod::MyEnum::MyField(1, 1); | ||
264 | } | ||
265 | |||
266 | pub mod my_other_mod { | ||
267 | fn another_fn() { | ||
268 | let m = MyEnum::MyField(1, 1); | ||
269 | } | ||
270 | |||
271 | pub enum MyEnum { | ||
272 | <|>MyField(u8, u8), | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | fn another_fn() { | ||
278 | let m = my_mod::my_other_mod::MyEnum::MyField(1, 1); | ||
279 | }"#, | ||
280 | r#"use my_mod::my_other_mod::MyField; | ||
281 | |||
282 | mod my_mod { | ||
283 | use my_other_mod::MyField; | ||
284 | |||
285 | fn another_fn() { | ||
286 | let m = my_other_mod::MyEnum::MyField(MyField(1, 1)); | ||
287 | } | ||
288 | |||
289 | pub mod my_other_mod { | ||
290 | fn another_fn() { | ||
291 | let m = MyEnum::MyField(MyField(1, 1)); | ||
292 | } | ||
293 | |||
294 | pub struct MyField(pub u8, pub u8); | ||
295 | |||
296 | pub enum MyEnum { | ||
297 | MyField(MyField), | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | fn another_fn() { | ||
303 | let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1)); | ||
304 | }"#, | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | fn check_not_applicable(ra_fixture: &str) { | ||
309 | let fixture = | ||
310 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
311 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
312 | } | ||
313 | |||
314 | #[test] | ||
315 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | ||
316 | check_not_applicable("enum A { <|>One }"); | ||
317 | } | ||
318 | |||
319 | #[test] | ||
320 | fn test_extract_enum_not_applicable_if_struct_exists() { | ||
321 | check_not_applicable( | ||
322 | r#"struct One; | ||
323 | enum A { <|>One(u8) }"#, | ||
324 | ); | ||
325 | } | ||
326 | } | ||
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_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 7ad941279..fe03b509e 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -250,7 +250,7 @@ impl ProjectWorkspace { | |||
250 | 250 | ||
251 | pub fn to_crate_graph( | 251 | pub fn to_crate_graph( |
252 | &self, | 252 | &self, |
253 | default_cfg_options: &CfgOptions, | 253 | target: Option<&str>, |
254 | extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>, | 254 | extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>, |
255 | proc_macro_client: &ProcMacroClient, | 255 | proc_macro_client: &ProcMacroClient, |
256 | load: &mut dyn FnMut(&Path) -> Option<FileId>, | 256 | load: &mut dyn FnMut(&Path) -> Option<FileId>, |
@@ -269,7 +269,7 @@ impl ProjectWorkspace { | |||
269 | json_project::Edition::Edition2018 => Edition::Edition2018, | 269 | json_project::Edition::Edition2018 => Edition::Edition2018, |
270 | }; | 270 | }; |
271 | let cfg_options = { | 271 | let cfg_options = { |
272 | let mut opts = default_cfg_options.clone(); | 272 | let mut opts = CfgOptions::default(); |
273 | for cfg in &krate.cfg { | 273 | for cfg in &krate.cfg { |
274 | match cfg.find('=') { | 274 | match cfg.find('=') { |
275 | None => opts.insert_atom(cfg.into()), | 275 | None => opts.insert_atom(cfg.into()), |
@@ -343,18 +343,13 @@ impl ProjectWorkspace { | |||
343 | } | 343 | } |
344 | } | 344 | } |
345 | ProjectWorkspace::Cargo { cargo, sysroot } => { | 345 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
346 | let mut cfg_options = get_rustc_cfg_options(target); | ||
347 | |||
346 | let sysroot_crates: FxHashMap<_, _> = sysroot | 348 | let sysroot_crates: FxHashMap<_, _> = sysroot |
347 | .crates() | 349 | .crates() |
348 | .filter_map(|krate| { | 350 | .filter_map(|krate| { |
349 | let file_id = load(&sysroot[krate].root)?; | 351 | let file_id = load(&sysroot[krate].root)?; |
350 | 352 | ||
351 | // Crates from sysroot have `cfg(test)` disabled | ||
352 | let cfg_options = { | ||
353 | let mut opts = default_cfg_options.clone(); | ||
354 | opts.remove_atom("test"); | ||
355 | opts | ||
356 | }; | ||
357 | |||
358 | let env = Env::default(); | 353 | let env = Env::default(); |
359 | let extern_source = ExternSource::default(); | 354 | let extern_source = ExternSource::default(); |
360 | let proc_macro = vec![]; | 355 | let proc_macro = vec![]; |
@@ -365,7 +360,7 @@ impl ProjectWorkspace { | |||
365 | file_id, | 360 | file_id, |
366 | Edition::Edition2018, | 361 | Edition::Edition2018, |
367 | Some(crate_name), | 362 | Some(crate_name), |
368 | cfg_options, | 363 | cfg_options.clone(), |
369 | env, | 364 | env, |
370 | extern_source, | 365 | extern_source, |
371 | proc_macro, | 366 | proc_macro, |
@@ -396,6 +391,10 @@ impl ProjectWorkspace { | |||
396 | 391 | ||
397 | let mut pkg_to_lib_crate = FxHashMap::default(); | 392 | let mut pkg_to_lib_crate = FxHashMap::default(); |
398 | let mut pkg_crates = FxHashMap::default(); | 393 | let mut pkg_crates = FxHashMap::default(); |
394 | |||
395 | // Add test cfg for non-sysroot crates | ||
396 | cfg_options.insert_atom("test".into()); | ||
397 | |||
399 | // Next, create crates for each package, target pair | 398 | // Next, create crates for each package, target pair |
400 | for pkg in cargo.packages() { | 399 | for pkg in cargo.packages() { |
401 | let mut lib_tgt = None; | 400 | let mut lib_tgt = None; |
@@ -404,7 +403,7 @@ impl ProjectWorkspace { | |||
404 | if let Some(file_id) = load(root) { | 403 | if let Some(file_id) = load(root) { |
405 | let edition = cargo[pkg].edition; | 404 | let edition = cargo[pkg].edition; |
406 | let cfg_options = { | 405 | let cfg_options = { |
407 | let mut opts = default_cfg_options.clone(); | 406 | let mut opts = cfg_options.clone(); |
408 | for feature in cargo[pkg].features.iter() { | 407 | for feature in cargo[pkg].features.iter() { |
409 | opts.insert_key_value("feature".into(), feature.into()); | 408 | opts.insert_key_value("feature".into(), feature.into()); |
410 | } | 409 | } |
@@ -561,7 +560,7 @@ impl ProjectWorkspace { | |||
561 | } | 560 | } |
562 | } | 561 | } |
563 | 562 | ||
564 | pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | 563 | fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { |
565 | let mut cfg_options = CfgOptions::default(); | 564 | let mut cfg_options = CfgOptions::default(); |
566 | 565 | ||
567 | // Some nightly-only cfgs, which are required for stdlib | 566 | // Some nightly-only cfgs, which are required for stdlib |
@@ -579,7 +578,7 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | |||
579 | let mut cmd = Command::new(ra_toolchain::rustc()); | 578 | let mut cmd = Command::new(ra_toolchain::rustc()); |
580 | cmd.args(&["--print", "cfg", "-O"]); | 579 | cmd.args(&["--print", "cfg", "-O"]); |
581 | if let Some(target) = target { | 580 | if let Some(target) = target { |
582 | cmd.args(&["--target", target.as_str()]); | 581 | cmd.args(&["--target", target]); |
583 | } | 582 | } |
584 | let output = output(cmd)?; | 583 | let output = output(cmd)?; |
585 | Ok(String::from_utf8(output.stdout)?) | 584 | Ok(String::from_utf8(output.stdout)?) |
@@ -601,6 +600,8 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions { | |||
601 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | 600 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), |
602 | } | 601 | } |
603 | 602 | ||
603 | cfg_options.insert_atom("debug_assertion".into()); | ||
604 | |||
604 | cfg_options | 605 | cfg_options |
605 | } | 606 | } |
606 | 607 | ||
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index c7e86fe0c..8f2aeac77 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -8,8 +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, ProjectManifest, | 11 | CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, |
12 | ProjectWorkspace, | ||
13 | }; | 12 | }; |
14 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 14 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -148,26 +147,14 @@ pub(crate) fn load( | |||
148 | } | 147 | } |
149 | } | 148 | } |
150 | 149 | ||
151 | // FIXME: cfg options? | 150 | let crate_graph = |
152 | let default_cfg_options = { | 151 | ws.to_crate_graph(None, &extern_source_roots, proc_macro_client, &mut |path: &Path| { |
153 | let mut opts = get_rustc_cfg_options(None); | ||
154 | opts.insert_atom("test".into()); | ||
155 | opts.insert_atom("debug_assertion".into()); | ||
156 | opts | ||
157 | }; | ||
158 | |||
159 | let crate_graph = ws.to_crate_graph( | ||
160 | &default_cfg_options, | ||
161 | &extern_source_roots, | ||
162 | proc_macro_client, | ||
163 | &mut |path: &Path| { | ||
164 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs | 152 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs |
165 | let path = path.canonicalize().ok()?; | 153 | let path = path.canonicalize().ok()?; |
166 | let vfs_file = vfs.load(&path); | 154 | let vfs_file = vfs.load(&path); |
167 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 155 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); |
168 | vfs_file.map(vfs_file_to_id) | 156 | vfs_file.map(vfs_file_to_id) |
169 | }, | 157 | }); |
170 | ); | ||
171 | log::debug!("crate graph: {:?}", crate_graph); | 158 | log::debug!("crate graph: {:?}", crate_graph); |
172 | analysis_change.set_crate_graph(crate_graph); | 159 | analysis_change.set_crate_graph(crate_graph); |
173 | 160 | ||
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 0bebb5bf6..73b0f881d 100644 --- a/crates/rust-analyzer/src/global_state.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; |
@@ -135,14 +135,6 @@ impl GlobalState { | |||
135 | } | 135 | } |
136 | } | 136 | } |
137 | 137 | ||
138 | // FIXME: Read default cfgs from config | ||
139 | let default_cfg_options = { | ||
140 | let mut opts = get_rustc_cfg_options(config.cargo.target.as_ref()); | ||
141 | opts.insert_atom("test".into()); | ||
142 | opts.insert_atom("debug_assertion".into()); | ||
143 | opts | ||
144 | }; | ||
145 | |||
146 | let proc_macro_client = match &config.proc_macro_srv { | 138 | let proc_macro_client = match &config.proc_macro_srv { |
147 | None => ProcMacroClient::dummy(), | 139 | None => ProcMacroClient::dummy(), |
148 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { | 140 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { |
@@ -168,7 +160,7 @@ impl GlobalState { | |||
168 | }; | 160 | }; |
169 | for ws in workspaces.iter() { | 161 | for ws in workspaces.iter() { |
170 | crate_graph.extend(ws.to_crate_graph( | 162 | crate_graph.extend(ws.to_crate_graph( |
171 | &default_cfg_options, | 163 | config.cargo.target.as_deref(), |
172 | &extern_source_roots, | 164 | &extern_source_roots, |
173 | &proc_macro_client, | 165 | &proc_macro_client, |
174 | &mut load, | 166 | &mut load, |