aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/semantics.rs8
-rw-r--r--crates/ra_hir_def/src/body.rs4
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs5
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs19
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs40
-rw-r--r--crates/ra_ide/src/diagnostics.rs72
-rw-r--r--crates/ra_ide/src/marks.rs1
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml1
-rw-r--r--crates/ra_proc_macro_srv/src/dylib.rs77
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs4
15 files changed, 175 insertions, 71 deletions
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
21use crate::{ 21use 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
17use std::{any::Any, fmt}; 17use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; 19use ra_syntax::{SyntaxNode, SyntaxNodePtr};
20 20
21use crate::{db::AstDatabase, InFile}; 21use crate::{db::AstDatabase, InFile};
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub 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
152fn add_type_alias_impl( 152fn 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)]
219mod tests { 219mod 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
3use hir::ScopeDef;
4use test_utils::tested_by;
5
3use crate::completion::{CompletionContext, Completions}; 6use crate::completion::{CompletionContext, Completions};
7use ra_syntax::AstNode;
4 8
5pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(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)]
21mod tests { 35mod 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
3use std::cell::RefCell; 7use 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" }
14ra_proc_macro = { path = "../ra_proc_macro" } 14ra_proc_macro = { path = "../ra_proc_macro" }
15goblin = "0.2.1" 15goblin = "0.2.1"
16libloading = "0.6.0" 16libloading = "0.6.0"
17memmap = "0.7"
17test_utils = { path = "../test_utils" } 18test_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
3use crate::{proc_macro::bridge, rustc_server::TokenStream}; 3use crate::{proc_macro::bridge, rustc_server::TokenStream};
4use std::fs::File;
4use std::path::Path; 5use std::path::Path;
5 6
6use goblin::{mach::Mach, Object}; 7use goblin::{mach::Mach, Object};
7use libloading::Library; 8use libloading::Library;
9use memmap::Mmap;
8use ra_proc_macro::ProcMacroKind; 10use ra_proc_macro::ProcMacroKind;
9 11
10use std::io::Error as IoError; 12use 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
19fn get_symbols_from_lib(file: &Path) -> Result<Vec<String>, IoError> { 21fn is_derive_registrar_symbol(symbol: &str) -> bool {
20 let buffer = std::fs::read(file)?; 22 symbol.contains(NEW_REGISTRAR_SYMBOL)
23}
24
25fn 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
59fn is_derive_registrar_symbol(symbol: &str) -> bool {
60 symbol.contains(NEW_REGISTRAR_SYMBOL)
61}
62
63fn 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 }