diff options
-rw-r--r-- | Cargo.lock | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_def/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 19 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_unqualified_path.rs | 40 | ||||
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 72 | ||||
-rw-r--r-- | crates/ra_ide/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_proc_macro_srv/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_proc_macro_srv/src/dylib.rs | 77 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 4 | ||||
-rw-r--r-- | xtask/tests/tidy-tests/main.rs | 6 |
17 files changed, 189 insertions, 74 deletions
diff --git a/Cargo.lock b/Cargo.lock index 89a734c9b..3826ae1c6 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -676,6 +676,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
676 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" | 676 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" |
677 | 677 | ||
678 | [[package]] | 678 | [[package]] |
679 | name = "memmap" | ||
680 | version = "0.7.0" | ||
681 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
682 | checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" | ||
683 | dependencies = [ | ||
684 | "libc", | ||
685 | "winapi 0.3.8", | ||
686 | ] | ||
687 | |||
688 | [[package]] | ||
679 | name = "memoffset" | 689 | name = "memoffset" |
680 | version = "0.5.4" | 690 | version = "0.5.4" |
681 | source = "registry+https://github.com/rust-lang/crates.io-index" | 691 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1112,6 +1122,7 @@ dependencies = [ | |||
1112 | "difference", | 1122 | "difference", |
1113 | "goblin", | 1123 | "goblin", |
1114 | "libloading", | 1124 | "libloading", |
1125 | "memmap", | ||
1115 | "ra_mbe", | 1126 | "ra_mbe", |
1116 | "ra_proc_macro", | 1127 | "ra_proc_macro", |
1117 | "ra_tt", | 1128 | "ra_tt", |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 2707e422d..0b477f0e9 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -20,6 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
20 | 20 | ||
21 | use crate::{ | 21 | use crate::{ |
22 | db::HirDatabase, | 22 | db::HirDatabase, |
23 | diagnostics::Diagnostic, | ||
23 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 24 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
24 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 25 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
25 | AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, | 26 | AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, |
@@ -126,6 +127,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
126 | original_range(self.db, node.as_ref()) | 127 | original_range(self.db, node.as_ref()) |
127 | } | 128 | } |
128 | 129 | ||
130 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
131 | let src = diagnostics.source(); | ||
132 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | ||
133 | let node = src.value.to_node(&root); | ||
134 | original_range(self.db, src.with_value(&node)) | ||
135 | } | ||
136 | |||
129 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 137 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
130 | let node = self.find_file(node); | 138 | let node = self.find_file(node); |
131 | node.ancestors_with_macros(self.db).map(|it| it.value) | 139 | node.ancestors_with_macros(self.db).map(|it| it.value) |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index eafaf48c1..3b169440a 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -210,7 +210,7 @@ pub struct BodySourceMap { | |||
210 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | 210 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, |
211 | pat_map: FxHashMap<PatSource, PatId>, | 211 | pat_map: FxHashMap<PatSource, PatId>, |
212 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | 212 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, |
213 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | 213 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>, |
214 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | 214 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, |
215 | } | 215 | } |
216 | 216 | ||
@@ -303,7 +303,7 @@ impl BodySourceMap { | |||
303 | self.pat_map.get(&src).cloned() | 303 | self.pat_map.get(&src).cloned() |
304 | } | 304 | } |
305 | 305 | ||
306 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | 306 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { |
307 | self.field_map[&(expr, field)].clone() | 307 | self.field_map[&(expr, field)].clone() |
308 | } | 308 | } |
309 | } | 309 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 0679ffa1e..82a52804d 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -320,7 +320,8 @@ impl ExprCollector<'_> { | |||
320 | 320 | ||
321 | let res = self.alloc_expr(record_lit, syntax_ptr); | 321 | let res = self.alloc_expr(record_lit, syntax_ptr); |
322 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | 322 | for (i, ptr) in field_ptrs.into_iter().enumerate() { |
323 | self.source_map.field_map.insert((res, i), ptr); | 323 | let src = self.expander.to_source(ptr); |
324 | self.source_map.field_map.insert((res, i), src); | ||
324 | } | 325 | } |
325 | res | 326 | res |
326 | } | 327 | } |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index cfa0f2f76..510c5e064 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule { | |||
20 | "unresolved module".to_string() | 20 | "unresolved module".to_string() |
21 | } | 21 | } |
22 | fn source(&self) -> InFile<SyntaxNodePtr> { | 22 | fn source(&self) -> InFile<SyntaxNodePtr> { |
23 | InFile { file_id: self.file, value: self.decl.clone().into() } | 23 | InFile::new(self.file, self.decl.clone().into()) |
24 | } | 24 | } |
25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
26 | self | 26 | self |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs index 108c1e38c..99209c6e8 100644 --- a/crates/ra_hir_expand/src/diagnostics.rs +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -16,16 +16,13 @@ | |||
16 | 16 | ||
17 | use std::{any::Any, fmt}; | 17 | use std::{any::Any, fmt}; |
18 | 18 | ||
19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; | 19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr}; |
20 | 20 | ||
21 | use crate::{db::AstDatabase, InFile}; | 21 | use crate::{db::AstDatabase, InFile}; |
22 | 22 | ||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
24 | fn message(&self) -> String; | 24 | fn message(&self) -> String; |
25 | fn source(&self) -> InFile<SyntaxNodePtr>; | 25 | fn source(&self) -> InFile<SyntaxNodePtr>; |
26 | fn highlight_range(&self) -> TextRange { | ||
27 | self.source().value.range() | ||
28 | } | ||
29 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 26 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
30 | } | 27 | } |
31 | 28 | ||
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 927896d6f..c8fd54861 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | fn source(&self) -> InFile<SyntaxNodePtr> { | 23 | fn source(&self) -> InFile<SyntaxNodePtr> { |
24 | InFile { file_id: self.file, value: self.field.clone().into() } | 24 | InFile::new(self.file, self.field.clone().into()) |
25 | } | 25 | } |
26 | 26 | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 246b0e9be..b6d9b3438 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -682,10 +682,10 @@ mod diagnostics { | |||
682 | ) { | 682 | ) { |
683 | match self { | 683 | match self { |
684 | InferenceDiagnostic::NoSuchField { expr, field } => { | 684 | InferenceDiagnostic::NoSuchField { expr, field } => { |
685 | let file = owner.lookup(db.upcast()).source(db.upcast()).file_id; | 685 | let source = owner.lookup(db.upcast()).source(db.upcast()); |
686 | let (_, source_map) = db.body_with_source_map(owner.into()); | 686 | let (_, source_map) = db.body_with_source_map(owner.into()); |
687 | let field = source_map.field_syntax(*expr, *field); | 687 | let field = source_map.field_syntax(*expr, *field); |
688 | sink.push(NoSuchField { file, field }) | 688 | sink.push(NoSuchField { file: source.file_id, field: field.value }) |
689 | } | 689 | } |
690 | } | 690 | } |
691 | } | 691 | } |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index fab02945c..2ec0e7ce9 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -142,11 +142,11 @@ fn add_function_impl( | |||
142 | CompletionItemKind::Function | 142 | CompletionItemKind::Function |
143 | }; | 143 | }; |
144 | 144 | ||
145 | let snippet = format!("{} {{}}", display); | 145 | let snippet = format!("{} {{\n $0\n}}", display); |
146 | 146 | ||
147 | let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); | 147 | let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); |
148 | 148 | ||
149 | builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); | 149 | builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); |
150 | } | 150 | } |
151 | 151 | ||
152 | fn add_type_alias_impl( | 152 | fn add_type_alias_impl( |
@@ -217,9 +217,10 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { | |||
217 | 217 | ||
218 | #[cfg(test)] | 218 | #[cfg(test)] |
219 | mod tests { | 219 | mod tests { |
220 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
221 | use insta::assert_debug_snapshot; | 220 | use insta::assert_debug_snapshot; |
222 | 221 | ||
222 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | ||
223 | |||
223 | fn complete(code: &str) -> Vec<CompletionItem> { | 224 | fn complete(code: &str) -> Vec<CompletionItem> { |
224 | do_completion(code, CompletionKind::Magic) | 225 | do_completion(code, CompletionKind::Magic) |
225 | } | 226 | } |
@@ -255,7 +256,7 @@ mod tests { | |||
255 | label: "fn test()", | 256 | label: "fn test()", |
256 | source_range: [209; 210), | 257 | source_range: [209; 210), |
257 | delete: [209; 210), | 258 | delete: [209; 210), |
258 | insert: "fn test() {}", | 259 | insert: "fn test() {\n $0\n}", |
259 | kind: Function, | 260 | kind: Function, |
260 | lookup: "test", | 261 | lookup: "test", |
261 | }, | 262 | }, |
@@ -313,7 +314,7 @@ mod tests { | |||
313 | label: "fn test()", | 314 | label: "fn test()", |
314 | source_range: [139; 140), | 315 | source_range: [139; 140), |
315 | delete: [139; 140), | 316 | delete: [139; 140), |
316 | insert: "fn test() {}", | 317 | insert: "fn test() {\n $0\n}", |
317 | kind: Function, | 318 | kind: Function, |
318 | lookup: "test", | 319 | lookup: "test", |
319 | }, | 320 | }, |
@@ -342,7 +343,7 @@ mod tests { | |||
342 | label: "fn foo()", | 343 | label: "fn foo()", |
343 | source_range: [141; 142), | 344 | source_range: [141; 142), |
344 | delete: [138; 142), | 345 | delete: [138; 142), |
345 | insert: "fn foo() {}", | 346 | insert: "fn foo() {\n $0\n}", |
346 | kind: Function, | 347 | kind: Function, |
347 | lookup: "foo", | 348 | lookup: "foo", |
348 | }, | 349 | }, |
@@ -374,7 +375,7 @@ mod tests { | |||
374 | label: "fn foo_bar()", | 375 | label: "fn foo_bar()", |
375 | source_range: [200; 201), | 376 | source_range: [200; 201), |
376 | delete: [197; 201), | 377 | delete: [197; 201), |
377 | insert: "fn foo_bar() {}", | 378 | insert: "fn foo_bar() {\n $0\n}", |
378 | kind: Function, | 379 | kind: Function, |
379 | lookup: "foo_bar", | 380 | lookup: "foo_bar", |
380 | }, | 381 | }, |
@@ -425,7 +426,7 @@ mod tests { | |||
425 | label: "fn foo()", | 426 | label: "fn foo()", |
426 | source_range: [144; 145), | 427 | source_range: [144; 145), |
427 | delete: [141; 145), | 428 | delete: [141; 145), |
428 | insert: "fn foo<T>() {}", | 429 | insert: "fn foo<T>() {\n $0\n}", |
429 | kind: Function, | 430 | kind: Function, |
430 | lookup: "foo", | 431 | lookup: "foo", |
431 | }, | 432 | }, |
@@ -454,7 +455,7 @@ mod tests { | |||
454 | label: "fn foo()", | 455 | label: "fn foo()", |
455 | source_range: [166; 167), | 456 | source_range: [166; 167), |
456 | delete: [163; 167), | 457 | delete: [163; 167), |
457 | insert: "fn foo<T>()\nwhere T: Into<String> {}", | 458 | insert: "fn foo<T>()\nwhere T: Into<String> {\n $0\n}", |
458 | kind: Function, | 459 | kind: Function, |
459 | lookup: "foo", | 460 | lookup: "foo", |
460 | }, | 461 | }, |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index 2d8e0776c..ad5fdcc4e 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -1,6 +1,10 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use hir::ScopeDef; | ||
4 | use test_utils::tested_by; | ||
5 | |||
3 | use crate::completion::{CompletionContext, Completions}; | 6 | use crate::completion::{CompletionContext, Completions}; |
7 | use ra_syntax::AstNode; | ||
4 | 8 | ||
5 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
6 | if !ctx.is_trivial_path { | 10 | if !ctx.is_trivial_path { |
@@ -14,12 +18,23 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
14 | return; | 18 | return; |
15 | } | 19 | } |
16 | 20 | ||
17 | ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); | 21 | ctx.scope().process_all_names(&mut |name, res| { |
22 | if ctx.use_item_syntax.is_some() { | ||
23 | if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { | ||
24 | if name_ref.syntax().text() == name.to_string().as_str() { | ||
25 | tested_by!(self_fulfilling_completion); | ||
26 | return; | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | acc.add_resolution(ctx, name.to_string(), &res) | ||
31 | }); | ||
18 | } | 32 | } |
19 | 33 | ||
20 | #[cfg(test)] | 34 | #[cfg(test)] |
21 | mod tests { | 35 | mod tests { |
22 | use insta::assert_debug_snapshot; | 36 | use insta::assert_debug_snapshot; |
37 | use test_utils::covers; | ||
23 | 38 | ||
24 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 39 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; |
25 | 40 | ||
@@ -28,6 +43,29 @@ mod tests { | |||
28 | } | 43 | } |
29 | 44 | ||
30 | #[test] | 45 | #[test] |
46 | fn self_fulfilling_completion() { | ||
47 | covers!(self_fulfilling_completion); | ||
48 | assert_debug_snapshot!( | ||
49 | do_reference_completion( | ||
50 | r#" | ||
51 | use foo<|> | ||
52 | use std::collections; | ||
53 | "#, | ||
54 | ), | ||
55 | @r###" | ||
56 | [ | ||
57 | CompletionItem { | ||
58 | label: "collections", | ||
59 | source_range: [21; 24), | ||
60 | delete: [21; 24), | ||
61 | insert: "collections", | ||
62 | }, | ||
63 | ] | ||
64 | "### | ||
65 | ); | ||
66 | } | ||
67 | |||
68 | #[test] | ||
31 | fn bind_pat_and_path_ignore_at() { | 69 | fn bind_pat_and_path_ignore_at() { |
32 | assert_debug_snapshot!( | 70 | assert_debug_snapshot!( |
33 | do_reference_completion( | 71 | do_reference_completion( |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 901ad104c..e7e201709 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -1,4 +1,8 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Collects diagnostics & fixits for a single file. |
2 | //! | ||
3 | //! The tricky bit here is that diagnostics are produced by hir in terms of | ||
4 | //! macro-expanded files, but we need to present them to the users in terms of | ||
5 | //! original files. So we need to map the ranges. | ||
2 | 6 | ||
3 | use std::cell::RefCell; | 7 | use std::cell::RefCell; |
4 | 8 | ||
@@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
46 | let mut sink = DiagnosticSink::new(|d| { | 50 | let mut sink = DiagnosticSink::new(|d| { |
47 | res.borrow_mut().push(Diagnostic { | 51 | res.borrow_mut().push(Diagnostic { |
48 | message: d.message(), | 52 | message: d.message(), |
49 | range: d.highlight_range(), | 53 | range: sema.diagnostics_range(d).range, |
50 | severity: Severity::Error, | 54 | severity: Severity::Error, |
51 | fix: None, | 55 | fix: None, |
52 | }) | 56 | }) |
@@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
62 | let create_file = FileSystemEdit::CreateFile { source_root, path }; | 66 | let create_file = FileSystemEdit::CreateFile { source_root, path }; |
63 | let fix = SourceChange::file_system_edit("create module", create_file); | 67 | let fix = SourceChange::file_system_edit("create module", create_file); |
64 | res.borrow_mut().push(Diagnostic { | 68 | res.borrow_mut().push(Diagnostic { |
65 | range: d.highlight_range(), | 69 | range: sema.diagnostics_range(d).range, |
66 | message: d.message(), | 70 | message: d.message(), |
67 | severity: Severity::Error, | 71 | severity: Severity::Error, |
68 | fix: Some(fix), | 72 | fix: Some(fix), |
@@ -95,7 +99,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
95 | }; | 99 | }; |
96 | 100 | ||
97 | res.borrow_mut().push(Diagnostic { | 101 | res.borrow_mut().push(Diagnostic { |
98 | range: d.highlight_range(), | 102 | range: sema.diagnostics_range(d).range, |
99 | message: d.message(), | 103 | message: d.message(), |
100 | severity: Severity::Error, | 104 | severity: Severity::Error, |
101 | fix, | 105 | fix, |
@@ -103,7 +107,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
103 | }) | 107 | }) |
104 | .on::<hir::diagnostics::MissingMatchArms, _>(|d| { | 108 | .on::<hir::diagnostics::MissingMatchArms, _>(|d| { |
105 | res.borrow_mut().push(Diagnostic { | 109 | res.borrow_mut().push(Diagnostic { |
106 | range: d.highlight_range(), | 110 | range: sema.diagnostics_range(d).range, |
107 | message: d.message(), | 111 | message: d.message(), |
108 | severity: Severity::Error, | 112 | severity: Severity::Error, |
109 | fix: None, | 113 | fix: None, |
@@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
115 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 119 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
116 | let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); | 120 | let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); |
117 | res.borrow_mut().push(Diagnostic { | 121 | res.borrow_mut().push(Diagnostic { |
118 | range: d.highlight_range(), | 122 | range: sema.diagnostics_range(d).range, |
119 | message: d.message(), | 123 | message: d.message(), |
120 | severity: Severity::Error, | 124 | severity: Severity::Error, |
121 | fix: Some(fix), | 125 | fix: Some(fix), |
@@ -622,6 +626,62 @@ mod tests { | |||
622 | } | 626 | } |
623 | 627 | ||
624 | #[test] | 628 | #[test] |
629 | fn range_mapping_out_of_macros() { | ||
630 | let (analysis, file_id) = single_file( | ||
631 | r" | ||
632 | fn some() {} | ||
633 | fn items() {} | ||
634 | fn here() {} | ||
635 | |||
636 | macro_rules! id { | ||
637 | ($($tt:tt)*) => { $($tt)*}; | ||
638 | } | ||
639 | |||
640 | fn main() { | ||
641 | let _x = id![Foo { a: 42 }]; | ||
642 | } | ||
643 | |||
644 | pub struct Foo { | ||
645 | pub a: i32, | ||
646 | pub b: i32, | ||
647 | } | ||
648 | ", | ||
649 | ); | ||
650 | let diagnostics = analysis.diagnostics(file_id).unwrap(); | ||
651 | assert_debug_snapshot!(diagnostics, @r###" | ||
652 | [ | ||
653 | Diagnostic { | ||
654 | message: "Missing structure fields:\n- b", | ||
655 | range: [224; 233), | ||
656 | fix: Some( | ||
657 | SourceChange { | ||
658 | label: "fill struct fields", | ||
659 | source_file_edits: [ | ||
660 | SourceFileEdit { | ||
661 | file_id: FileId( | ||
662 | 1, | ||
663 | ), | ||
664 | edit: TextEdit { | ||
665 | atoms: [ | ||
666 | AtomTextEdit { | ||
667 | delete: [3; 9), | ||
668 | insert: "{a:42, b: ()}", | ||
669 | }, | ||
670 | ], | ||
671 | }, | ||
672 | }, | ||
673 | ], | ||
674 | file_system_edits: [], | ||
675 | cursor_position: None, | ||
676 | }, | ||
677 | ), | ||
678 | severity: Error, | ||
679 | }, | ||
680 | ] | ||
681 | "###); | ||
682 | } | ||
683 | |||
684 | #[test] | ||
625 | fn test_check_unnecessary_braces_in_use_statement() { | 685 | fn test_check_unnecessary_braces_in_use_statement() { |
626 | check_not_applicable( | 686 | check_not_applicable( |
627 | " | 687 | " |
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index 5e1f135c5..eee44e886 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs | |||
@@ -8,4 +8,5 @@ test_utils::marks!( | |||
8 | test_resolve_parent_module_on_module_decl | 8 | test_resolve_parent_module_on_module_decl |
9 | search_filters_by_range | 9 | search_filters_by_range |
10 | dont_insert_macro_call_parens_unncessary | 10 | dont_insert_macro_call_parens_unncessary |
11 | self_fulfilling_completion | ||
11 | ); | 12 | ); |
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index 1e0f50339..ac2d156dc 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml | |||
@@ -14,6 +14,7 @@ ra_mbe = { path = "../ra_mbe" } | |||
14 | ra_proc_macro = { path = "../ra_proc_macro" } | 14 | ra_proc_macro = { path = "../ra_proc_macro" } |
15 | goblin = "0.2.1" | 15 | goblin = "0.2.1" |
16 | libloading = "0.6.0" | 16 | libloading = "0.6.0" |
17 | memmap = "0.7" | ||
17 | test_utils = { path = "../test_utils" } | 18 | test_utils = { path = "../test_utils" } |
18 | 19 | ||
19 | [dev-dependencies] | 20 | [dev-dependencies] |
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs index ec63d587b..16bd7466e 100644 --- a/crates/ra_proc_macro_srv/src/dylib.rs +++ b/crates/ra_proc_macro_srv/src/dylib.rs | |||
@@ -1,10 +1,12 @@ | |||
1 | //! Handles dynamic library loading for proc macro | 1 | //! Handles dynamic library loading for proc macro |
2 | 2 | ||
3 | use crate::{proc_macro::bridge, rustc_server::TokenStream}; | 3 | use crate::{proc_macro::bridge, rustc_server::TokenStream}; |
4 | use std::fs::File; | ||
4 | use std::path::Path; | 5 | use std::path::Path; |
5 | 6 | ||
6 | use goblin::{mach::Mach, Object}; | 7 | use goblin::{mach::Mach, Object}; |
7 | use libloading::Library; | 8 | use libloading::Library; |
9 | use memmap::Mmap; | ||
8 | use ra_proc_macro::ProcMacroKind; | 10 | use ra_proc_macro::ProcMacroKind; |
9 | 11 | ||
10 | use std::io::Error as IoError; | 12 | use std::io::Error as IoError; |
@@ -16,55 +18,54 @@ fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> I | |||
16 | IoError::new(IoErrorKind::InvalidData, e) | 18 | IoError::new(IoErrorKind::InvalidData, e) |
17 | } | 19 | } |
18 | 20 | ||
19 | fn get_symbols_from_lib(file: &Path) -> Result<Vec<String>, IoError> { | 21 | fn is_derive_registrar_symbol(symbol: &str) -> bool { |
20 | let buffer = std::fs::read(file)?; | 22 | symbol.contains(NEW_REGISTRAR_SYMBOL) |
23 | } | ||
24 | |||
25 | fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> { | ||
26 | let file = File::open(file)?; | ||
27 | let buffer = unsafe { Mmap::map(&file)? }; | ||
21 | let object = Object::parse(&buffer).map_err(invalid_data_err)?; | 28 | let object = Object::parse(&buffer).map_err(invalid_data_err)?; |
22 | 29 | ||
23 | match object { | 30 | match object { |
24 | Object::Elf(elf) => { | 31 | Object::Elf(elf) => { |
25 | let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?; | 32 | let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?; |
26 | let names = symbols.iter().map(|s| s.to_string()).collect(); | 33 | let name = |
27 | Ok(names) | 34 | symbols.iter().find(|s| is_derive_registrar_symbol(s)).map(|s| s.to_string()); |
35 | Ok(name) | ||
28 | } | 36 | } |
29 | Object::PE(pe) => { | 37 | Object::PE(pe) => { |
30 | let symbol_names = | 38 | let name = pe |
31 | pe.exports.iter().flat_map(|s| s.name).map(|n| n.to_string()).collect(); | 39 | .exports |
32 | Ok(symbol_names) | 40 | .iter() |
41 | .flat_map(|s| s.name) | ||
42 | .find(|s| is_derive_registrar_symbol(s)) | ||
43 | .map(|s| s.to_string()); | ||
44 | Ok(name) | ||
33 | } | 45 | } |
34 | Object::Mach(mach) => match mach { | 46 | Object::Mach(Mach::Binary(binary)) => { |
35 | Mach::Binary(binary) => { | 47 | let exports = binary.exports().map_err(invalid_data_err)?; |
36 | let exports = binary.exports().map_err(invalid_data_err)?; | 48 | let name = exports |
37 | let names = exports | 49 | .iter() |
38 | .into_iter() | 50 | .map(|s| { |
39 | .map(|s| { | 51 | // In macos doc: |
40 | // In macos doc: | 52 | // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html |
41 | // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html | 53 | // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be |
42 | // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be | 54 | // prepended with an underscore. |
43 | // prepended with an underscore. | 55 | if s.name.starts_with("_") { |
44 | if s.name.starts_with("_") { | 56 | &s.name[1..] |
45 | s.name[1..].to_string() | 57 | } else { |
46 | } else { | 58 | &s.name |
47 | s.name | 59 | } |
48 | } | 60 | }) |
49 | }) | 61 | .find(|s| is_derive_registrar_symbol(s)) |
50 | .collect(); | 62 | .map(|s| s.to_string()); |
51 | Ok(names) | 63 | Ok(name) |
52 | } | 64 | } |
53 | Mach::Fat(_) => Ok(vec![]), | 65 | _ => Ok(None), |
54 | }, | ||
55 | Object::Archive(_) | Object::Unknown(_) => Ok(vec![]), | ||
56 | } | 66 | } |
57 | } | 67 | } |
58 | 68 | ||
59 | fn is_derive_registrar_symbol(symbol: &str) -> bool { | ||
60 | symbol.contains(NEW_REGISTRAR_SYMBOL) | ||
61 | } | ||
62 | |||
63 | fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> { | ||
64 | let symbols = get_symbols_from_lib(file)?; | ||
65 | Ok(symbols.into_iter().find(|s| is_derive_registrar_symbol(s))) | ||
66 | } | ||
67 | |||
68 | /// Loads dynamic library in platform dependent manner. | 69 | /// Loads dynamic library in platform dependent manner. |
69 | /// | 70 | /// |
70 | /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described | 71 | /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index eb9ac32c3..762f776fe 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -75,9 +75,7 @@ pub(crate) fn load_cargo( | |||
75 | let proc_macro_client = if !with_proc_macro { | 75 | let proc_macro_client = if !with_proc_macro { |
76 | ProcMacroClient::dummy() | 76 | ProcMacroClient::dummy() |
77 | } else { | 77 | } else { |
78 | let mut path = std::env::current_exe()?; | 78 | let path = std::env::current_exe()?; |
79 | path.pop(); | ||
80 | path.push("rust-analyzer"); | ||
81 | ProcMacroClient::extern_process(&path, &["proc-macro"]).unwrap() | 79 | ProcMacroClient::extern_process(&path, &["proc-macro"]).unwrap() |
82 | }; | 80 | }; |
83 | let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client); | 81 | let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 2b45f1310..3597a14e3 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -134,9 +134,7 @@ impl Config { | |||
134 | 134 | ||
135 | match get::<bool>(value, "/procMacro/enabled") { | 135 | match get::<bool>(value, "/procMacro/enabled") { |
136 | Some(true) => { | 136 | Some(true) => { |
137 | if let Ok(mut path) = std::env::current_exe() { | 137 | if let Ok(path) = std::env::current_exe() { |
138 | path.pop(); | ||
139 | path.push("rust-analyzer"); | ||
140 | self.proc_macro_srv = Some((path.to_string_lossy().to_string(), vec!["proc-macro".to_string()])); | 138 | self.proc_macro_srv = Some((path.to_string_lossy().to_string(), vec!["proc-macro".to_string()])); |
141 | } | 139 | } |
142 | } | 140 | } |
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy-tests/main.rs index 101ae19bd..ead642acc 100644 --- a/xtask/tests/tidy-tests/main.rs +++ b/xtask/tests/tidy-tests/main.rs | |||
@@ -35,7 +35,7 @@ fn check_todo(path: &Path, text: &str) { | |||
35 | } | 35 | } |
36 | if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { | 36 | if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { |
37 | panic!( | 37 | panic!( |
38 | "\nTODO markers should not be committed to the master branch,\n\ | 38 | "\nTODO markers or todo! macros should not be committed to the master branch,\n\ |
39 | use FIXME instead\n\ | 39 | use FIXME instead\n\ |
40 | {}\n", | 40 | {}\n", |
41 | path.display(), | 41 | path.display(), |
@@ -47,9 +47,9 @@ fn check_trailing_ws(path: &Path, text: &str) { | |||
47 | if is_exclude_dir(path, &["test_data"]) { | 47 | if is_exclude_dir(path, &["test_data"]) { |
48 | return; | 48 | return; |
49 | } | 49 | } |
50 | for line in text.lines() { | 50 | for (line_number, line) in text.lines().enumerate() { |
51 | if line.chars().last().map(char::is_whitespace) == Some(true) { | 51 | if line.chars().last().map(char::is_whitespace) == Some(true) { |
52 | panic!("Trailing whitespace in {}", path.display()) | 52 | panic!("Trailing whitespace in {} at line {}", path.display(), line_number) |
53 | } | 53 | } |
54 | } | 54 | } |
55 | } | 55 | } |